2012-05-09 21 views
0

状況: 私はユーザーモデルを持っています。 dbの属性 "meta_data"は "text"型のフィールドを表します。 モデルでは、それはカスタムクラスによってseriazized。 (serialize :meta_data, CustomJsonSerializer.newmysqlデータベースで検索 - シリアル化されていないデータ

つまり、ユーザーのインスタンスがある場合は、meta_dataと同じようにハッシュを使用できます。

User.first.meta_data['username'] 

問題:

私は与えられた文字列でユーザーを検索します検索機能を、記述する必要があります。私は手動の検索クエリをレールで実行することでそれを行うことができます。 User.where("email LIKE '%#{string}%'")... しかし、meta_dataはどうですか? LIKE文でもこのフィールドを検索する必要がありますか?私がそうするならば、それは発見された記録の関連性を低下させるでしょう。

例:

私は2人のユーザーがいます。そのうちの一つは、他の一つは "セルジオ" のようになりますデシベルで

メタデータがあるユーザ名 "パトリック" を持っている:

1){ユーザー名:パトリック}

2){ユーザー名:セルジオ}

私はsergioを探していますが、検索文字列 "ser" =>を入力しますが、1つではなく2つの結果があります。このmeta_data文字列 "{uSERname:Patrick}"も "ser"を持つので、このレコードは無関係です。

解決方法はありますか?

答えて

0

これは実際にシリアル化されたデータの問題です。理論的には、シリアライゼーションは非常に見分けがつかないアルゴリズムである可能性があります。ホフマンエンコーディングやその他の圧縮を行い、シリアライズをバイナリ形式で格納することができます。シリアライズではJSONを使用していて、文字列はシリアライズのサブ文字列として引き続き検索できるという前提に頼っています。

次に、問題は別の問題です。シリアライゼーションの他のデータは結果を乱すことがあります。

通常、データをシリアル化すると、検索できないという選択が行われます。

解決策は、コントロールする方法で追加するフィールドを追加することです。値フィールドを持ち、検索可能なパイプ(|)で区切られた値を格納します。したがって、データが{firstname: "Patrick"、lastname: "Stern"}の場合、meta_valuesフィールドは "Patrick | Stern"です。

また、入力値を#{}拡張した文字列ではwhereメソッドを使用しないでください。これはSQL攻撃に対して脆弱になります。代わりに使用します。

where("meta_values is like :pattern", pattern: "%#{string}%") 

私はそれが非常に違って見えるかもしれません知っているが、ActiveRecordのは、この方法で消毒を経由します。もし誰かが文字列にセミコロンを持っていれば、ActiveRecordは検索条件のセミコロンをエスケープします。

関連する問題