2010-12-02 7 views
5

나는 이것에 약간 좌절감을 느낍니다.Ruby rand()는 변수를 받아 들일 수 없습니까?

RoR 프로젝트의 최종 목표는 데이터베이스에서 임의의 단일 프로필을 가져 오는 것입니다.

는 뭔가처럼 될 것이라고 생각했다 : 그것은 0이 존재하지 않는 user_id 때문에 오류를 던지는 유지

@profile = Profile.find_by_user_id(rand(User.count)) 

, 그래서 나는 밖으로 그것의 부분 무슨 일이 일어나고 체크 아웃 뽑아 :

@r = rand(User.count) 

<%= @r %> 

이 값은 매번 0을 반환합니다. 무슨 일 이니? 이 테스트를 위해 5 명의 가짜 사용자와 5 개의 관련 프로필을 등록했습니다.

내가 Profile.find_by_user_id(rand(User.count))을하고 잘 작동

Profile.find_by_user_id(3) 

로 다시 작성합니다.

User.count도 작동합니다. 그래서 나는 rand()이 정적 정수가 아닌 다른 입력을 취할 수 없다고 생각합니다.

맞습니까? 무슨 일이야?

+1

rand (User.count)가 적합합니다. – drewrobb

+0

정말요? 알았어. 나는 무슨 일이 일어나는지보아야 할 것이다. 어쩌면 내가 중요한 것을 놓친 것일 수도있다. – Elxx

+0

앤드류에게 감사드립니다. 내 자신의 질문을 다시 읽으면 때때로 혼란스러워진다. D – Elxx

답변

9

보십시오 : 데이터베이스 나이로

Profile.first(:offset => rand(Profile.count)) 

, 사용자 레코드 특히 하나, 귀하의 ID 필드 순서에 차이가있을 것입니다. 무작위로 ID를 얻으려고하면 삭제 된 것을 임의로 잡으려고 시도 할 수 있기 때문에 실패 할 가능성이 있습니다.

대신 레코드 수를 계산 한 다음 무작위로 테이블로 오프셋하면 ID가 누락 될 가능성을 피할 수 있으며 기존 레코드에만 착신됩니다.

데이터베이스의 무결성은 매우 신중하게 감시하지 않는 한 문제는 몇 가지 문제로 실행할 수있는 OPS에서 다음 예 :

profile = Profile.find_by_user_id(rand(User.count)) 
문제가

는, 사용자 테이블이 동기화되지 할 가능성있다 프로필 테이블을 사용하여 다른 수의 레코드를 가질 수 있습니다. 예를 들어 User.count이 3이고 프로필에 2 개의 레코드가있는 경우 예외가 발생하여 실패한 조회가 발생할 수 있습니다.

+0

Perfect. 아주 잘 작동합니다. RAND/RANDOM =과 같은 특정 단계 데이터베이스 특정 기능을 수행하기 때문에 가장 좋은 대답으로 선택했습니다. – Elxx

+1

감사합니다. 네, 의도적으로 이식성을 유지하기 위해 DB 특성을 피했습니다. DBM에서 완전히 실행되도록 작성 될 수 있지만 쿼리는 특정 데이터베이스에 연결됩니다. 즉, 데이터베이스를 두 번 호출해야하지만 속도가 매우 빠르며 검색이 필요하지 않습니다. –

+0

항상 빠를 필요는 없습니다. 예를 들어, Postgres는 느린 COUNT (*) 쿼리에 대해 악명 높습니다. –

-3

찾아 ID IN 레일 아마 때문에 레일 단지 사람들이 합의 규칙입니다 Conventions Over Configuration 의미있는 디폴트이다

@profile = Profile.find_by_user_id(rand(User.count)) 
#This is redudent, all you need to code is: 
@profile = Profile.find(rand(User.count)) #default for Rails is ID 

0에 따라 오류 메시지 중복입니다.

레일을 사용할 때 사용자를 0으로 지정할 이유가 없으며 항상 1에서 시작하여 DHH가 더 읽기 쉽도록 지정합니다.

+0

이것은 내가 말할 수있는 한 그의 질문과는 아무런 관련이 없다. 나는 Profile.find (rand_int)가 Profile.find_by_user_id (rand_it)보다 더 합리적인 것에 동의하지만, find_by_user_id는 실제 의미에서 "중복"하지 않습니다. 나는 또한 귀하의 게시물의 나머지 부분에 대해 무엇을 말하고 있는지 전혀 모른다. – bnaul

+0

죄송합니다. 게시물을 더 이해하기 위해 노력할 것입니다. id와 user_id의 2 개의 열이 있기 때문에 Profile.find_by_user_id를 호출합니다. user_id 열을 기반으로 행을 선택하고 싶습니다. 그래서 매우 필요한 것입니다. – Elxx

4

rand (i)가 예상대로 작동하지 않는지는 잘 모르겠지만 (이것은 정상적으로 작동합니다), 그러나 이것은 무작위 프로파일을 관계없이 찾을 수있는 좋은 방법은 아닙니다. 프로필이 삭제되거나 프로필이없는 사용자가있는 경우이 작업은 실패합니다.

ActiveRecord를 사용하여 레일즈에서 이것을 효율적으로 수행 할 방법이 없다고 생각합니다. 적은 수의 사용자를 위해, 당신은 단지 Profile.find_all을 (할) 및 그 배열에서 임의의 프로파일을 선택,하지만 당신은 아마 StackOverflow의 많은 다른 질문이 있습니다

@profile = Profile.find_by_sql("SELECT * FROM profiles ORDER BY RAND() LIMIT 1").first 

같은 일을 더 나을 것입니다 수 SQL에서 임의의 레코드를 선택하는 방법; 이 방법이 가장 쉽다고 말하고 싶지만, 효율성에 대해 염려한다면 주변을 둘러보고 더 나은 구현 방법이 있는지 확인하십시오.

EDIT : find_by_sql은 배열을 반환하므로 단일 Profile을 얻으려면 .first를 수행해야합니다. 이 일반적으로 작동

@profile = Profile.first(:order => "RAND()") 

하지만 내가 읽은 것을 대비는 RAND() 명령은 MySQL로 특정 : 나는 레일에서 임의의 레코드를 가져하려는 경우

+0

나는 이것을 시험해 보겠다. 자신의 프로필을 삭제하는 사람들이 일을 망쳐 버리는 일은 결코 일어나지 않았습니다 .... 하, 테스트 케이스 작성을 시작해야합니다. – Elxx

+0

그가하고있는 방식이 가장 좋습니다 (Ruby에서 임의의 숫자를 생성하고 'id'열에서 검색). 실제로 원하는 행을 찾으려면 일정한 시간이 걸립니다. 이렇게하려면 임의의 숫자를 할당하기 위해 전체 테이블 스캔이 필요하며 O (n log n) 정렬을 사용하면 필요한 한 행을 반환 할 수 있습니다. –

+2

@Ken Bloom 사실입니다. 차이점은 광산이 실제로 작동한다는 것입니다.) 반면, OP에는 제가 언급 한 단점이 있습니다. DanneManne은 Rubyish와 비슷하지만 무작위 ID로 찾는 것은 위험합니다. while 루프에서 랩핑하고 찾을 때까지 계속 검색 할 수 있습니다. 완전한 데이터 세트는 더 빠르지 만 누락 행이 많은 행은 더 느립니다 (잠재적으로 하나가 아닌 많은 데이터베이스 요청을 만들 수 있음). – bnaul

1

, 나는 이런 식으로 뭔가를 이동 적어도 데이터베이스에 독립적이지는 않습니다. 다른 사람들은 RANDOM()을 사용할 수 있습니다.

관련 문제