2010-12-02 14 views
5

私はこれに少し戸惑いました。Ruby rand()は変数を受け入れることができません。

RoRプロジェクトの私の最終目標は、データベースから単一のランダムなプロファイルを取得することです。

私は次のようにそれがものになるだろう考えていた

user_id 0が存在しないため、それがエラーを投げまま、私はちょうど何が起こっているかをチェックするためにその一部を取り出し

@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

Andrewの編集に感謝します。私自身の質問を再読することで時々混乱してしまった= D – Elxx

答えて

9

してみてください。データベースの年齢として

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

、ユーザレコードで、特に1、あなたのIDフィールドのシーケンスにギャップが存在します。ランダムにIDを取得しようとすると、削除されたIDをランダムに取得しようとする可能性があるため、失敗する可能性があります。

代わりに、レコード数を数え、無作為にテーブルにオフセットすると、IDが不足している可能性を回避し、既存のレコードにのみ着くことができます。

データベースの整合性が非常に注意深く見守っされていない限り、問題はいくつかの問題に実行することができますのOPからの次の例:

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

問題があり、同期が外れするユーザーテーブルの可能性がありますプロファイルテーブルを使用して、異なる数のレコードを持つことができます。たとえば、User.countが3で、プロファイルに2つのレコードがある場合、失敗した検索の可能性があり、その結果例外が発生します。

+0

パーフェクト。非常にうまく動作します。 RAND/RANDOM =のようなデータベース固有の機能を備えているため、これを最善の答えとして選択しました。 – Elxx

+1

ありがとうございます。はい、私は意図的にそれを移植性を保つためにDBの詳細を避けました。 DBMで完全に実行するように記述できますが、それは特定のデータベースにクエリを結びつけます。つまり、データベースを2回呼び出す必要がありますが、それらは非常に高速であり、検索は必要ありません。 –

+0

必ずしも高速である必要はありません。たとえば、Postgresは遅いCOUNT(*)クエリでは有名です。 –

-3

見つけることによって、IDがRailsはおそらくRAILSだけの人が合意ルールです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

申し訳ありません私はポストをもっと理にかなっているようにしようとします。 Profile.find_by_user_idはidとuser_idという2つのカラムがあるので私はそれを呼び出します。 user_id列に基づいて行を選択したいとします。だから、非常に必要です。 – Elxx

4

rand(i)が期待どおりに動作しない理由は分かりませんが、これは無関係にランダムプロファイルを見つける良い方法ではありません。プロファイルが削除された場合、またはプロファイルのないユーザーがいる場合は失敗します。

ActiveRecordを使ってRailsでこれを行う効率的な方法はないと思います。少数のユーザーのために、あなたはProfile.find_all(単に行うことができます)、その配列からランダムなプロファイルを選択しますが、おそらくStackOverflowの上の他の多くの質問があります

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

のようなものをやったほうが良いと思いますどのようにSQLでランダムなレコードを選択するかについて。私はこれが一番簡単だと言っていますが、効率について懸念している場合は、もっと見栄えの良い実装があるかどうかを見てみましょう。

EDIT:find_by_sqlは配列を返します。したがって、単一のプロファイルを取得するには.firstを実行する必要があります。

+0

これを試してみます。彼らのプロフィールを削除する人々が物事を混乱させることは私には起こりませんでした....私はテストケースを書くことを開始する必要があります。 – Elxx

+0

彼がやっているやり方は最高です(Rubyで乱数を生成し、それを 'id'カラムで検索する) - 実際に彼が望む行を見つけるには一定の時間がかかります。それを自分のやり方で行うには、乱数を割り当てるための完全なテーブルスキャンと、必要な行を返す前にO(n log n)のソートが必要です。 –

+2

@Ken Bloomこれは本当です。違いは私が実際に働くということです)、OPには私が言及した欠点があります。 DanneManneは似ていてRubyishですが、ランダムなIDで検索するのは危険です。あなたはwhileループでそれをラップし、完全なデータセットでは高速ですが、多くの行が欠落している場合は遅くなります(潜在的に1つではなく多くのデータベースリクエストを作成する可能性があります)。 – bnaul

1

私はRailsの中にランダムにレコードを取得したい場合は、私はこのような何かに行く:

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

これを通常動作しますが、私が以前読んだから、RAND()コマンドは、MySQLに固有のものです少なくともデータベースには依存しません。他の人はRANDOM()を使うかもしれません。