1

Ruby on Rails を capistrano と git と組み合わせて使用​​すると、厄介な問題に遭遇しました..

次のようなインデックスアクションを持つコントローラー「人」があります。

def index
  @people = Person.find( :conditions => params[:search] )
end

Person テーブルにはブール値の「is_admin」列があります。一部の人々が管理者であり、一部が管理者ではない場合、http://localhost:3000/people?search[is_admin]=trueの get 呼び出しは、@people に一部のユーザーを入力する必要があります...そして、これは私のローカルに当てはまりますアプリを開発モードで実行すると、PC..

しかし.... サーバー アカウント ( railsplayground ) にデプロイすると、http://mydomain.com/people?search[is_admin]=true を呼び出して一致するアイテムが見つかりません。ただし、...?search[is_admin]=true...?search[is_admin]=1に変更すると、応答は期待どおりに管理者ユーザーを返します...

ローカル PC に戻ると、「true」の代わりに「1」を使用すると失敗します。

肝心なのは、

Person.find( :all, :conditions => { :is_admin => 'true' } )

私の開発環境で動作し、

Person.find( :all, :conditions => { :is_admin => 1 } )

デプロイされた環境で動作します。

どうしてこれなの?どうすれば修正できますか?

理想的には、次のようなリンクを配置したいと思います。

link_to( "Administrators", {
  :controller => '/people',
  :action => :index,
  :search => { :is_admin => true }
})

管理者のリストを取得します:)。

私の開発データベースはsqlite3ファイルであり、本番環境はmysqlデータベースであることに注意してください...

編集: ユーザー入力に対する異論は理解していますが、この例外的なケースでは、それは非常に小さな脅威です。また、現在のコードは、開発用 PC または運用アカウントのいずれかで完全に機能しますが、両方では機能しません。最も簡単な解決策は、sqlite3 がブール値を保存および相互運用する方法を変更するように思われるため、質問を「sqlite がブール値を保存する方法を変更するにはどうすればよいですか」に変更します... sqlite が mysql の動作を完全に模倣する場合、それは私の開発に役立ちます完全に必要です...

4

3 に答える 3

3

問題は、ブール値を文字列として渡し、最終的な動作がアクティブなデータベースに依存することです。詳しい説明はこちら。

params[:search]変数を読み取ると、内容は文字列で型はありません。これは、クエリ文字列が

params[:search][:is_admin] = "true"

実際に意味する

params[:search][:is_admin] = "true"
params[:search][:is_admin] = true

同様に、1 を渡すと、最終的には

params[:search][:is_admin] = "1"

とは異なります

params[:search][:is_admin] = 1

値をクエリに渡す場合、ブール値を渡していないため、値はデータベース アダプタによって変換されません。最終的なクエリの結果は次のようになります

SELECT * FROM `persons` WHERE `persons.is_admin` = 'true'

SQLite3 はブール値を t/f 文字列として格納します。trueとして保存され't'falseとして保存され'f'ます。true/false も理解しており、クエリを自動的に翻訳してくれると思います。反対に、MySQL は 0/1 と true/false しか理解せず、失敗します。

1の代わりに渡す動作を切り替えると、文字列を にtrue変換できないため、SQLite が失敗します。反対に、MySQL は可能であり、実際にそうしています。"1"'t'

どちらの場合も、あなたはそれを間違っています。文字列ではなくブール値を渡す必要があります。また、ユーザーの入力を信用してはいけません。

私の提案は、params[:search]摂食前にあなたを正常化することですPerson.find.

于 2010-02-06T19:39:53.120 に答える
2

sqlite と mysql の使用の違いが問題の原因だと思います。

しかし、クエリ文字列から直接条件付けされたアクティブ レコードを許可することは、私には悪い考えのように思えます。アプリが SQL インジェクション攻撃に対して無防備になる可能性があります。

于 2010-02-06T19:39:47.133 に答える
0

@Simone answer は、なぜそのような振る舞いをするのかを説明しています。sqlite3 と mysql の両方で正しい結果を得るには、以下を渡す必要があります。

Person.find( :all, :conditions => { :is_admin => true } )

params[:search][:something]次のような条件で正しいハッシュを作成できるよりも、パラメーターのレベルが 1 つしかない場合 (それ以上のものはありません):

my_conditions = Hash.new
params[:search].each do |item, value|
  my_conditions[item.to_sym] = value == 'true' ? true : value == 'false' ? false : value
end

すべての検索パラメーターを反復処理し、すべて'true'trueおよび'false'に変更しfalseます。他の値がある場合は、そのままにしておきます。もちろん、ここに任意のロジックを配置できます。ifまたは で書き換えることができるよりも複雑になる場合switch

あなたができるより:

Person.all(:conditions => my_conditions)
于 2010-02-06T20:51:32.940 に答える