あとは残ったメソッドをちょこちょこみよう。
ActiveRecord::Base#exists?
呼び出し方
find.exists?(1) find.exists?(:name=>"David") find.exists?(["name LIKE ?"], "%#{query}%")
コードはこんなの。
def exists?(id_or_conditions = {}) find_initial( :select => "#{quoted_table_name}.#{primary_key}", :conditions => expand_id_conditions(id_or_conditions)) ? true : false end
find_initial()で取得してるだけか。
お、知らないメソッド(expand_id_conditions)を見つけたので、調べよう。
ActiveRecord::Base#expand_id_conditions
def expand_id_conditions(id_or_conditions) case id_or_conditions when Array, Hash then id_or_conditions else sanitize_sql(primary_key => id_or_conditions) end end
- Array/Hashの時はそのまま返す。
- それ以外の時は、primary_keyとして返すんだな。だな。
ActiveRecord::Base#update
呼び出し方はこうか。フムフム。
Person.update(15, :user_name => 'Samuel', :group => 'expert') people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } } Person.update(people.keys, people.values)
コードはどんなことしてんのかな。
def update(id, attributes) if id.is_a?(Array) idx = -1 id.collect { |one_id| idx += 1; update(one_id, attributes[idx]) } else object = find(id) object.update_attributes(attributes) object end end
- idがArrayだったら複数行のupdateと判断して、複数行のupdateをしている。(自分自身を呼び出している)
- idがArrayじゃなければ、idで検索して、attributesを設定してupdateな。
引数のidの名前は、id_or_array_of_idとかだったらわかりやすい気がした。
そういえば、update_attributes()は何してるんだ?
ActiveRecord::Base#update_attributes
def update_attributes(attributes) self.attributes = attributes save end
自分のattributesを入れて、saveしているだけか。
save内では、SQL Injectionがおこせないので問題ないなー。
ActiveRecord::Base#delete
おお、しまった。delete()を忘れていた。
def delete(id) delete_all([ "#{connection.quote_column_name(primary_key)} IN (?)", id ]) end
delete_allでprimary_keyの値を渡しているのかな。
ActiveRecord::Base#delete_all
def delete_all(conditions = nil) sql = "DELETE FROM #{quoted_table_name} " add_conditions!(sql, conditions, scope(:find)) connection.delete(sql, "#{name} Delete all") end
add_conditions!はfindの時にでてきたな。
conditionsがArrayとかHashの場合に、sanitizeした WHERE句を作って
作ったクエリをconnection.delete() に渡す。
ActiveRecord::Base#destroy
クラスメソッドの方のdestroy
ActiveRecord::Base#destroyの#と何かで、クラスメソッドと、インスタンスメソッドの区別ができたような気がするんだけど、書き方知っている人いたら教えてください。*1
def destroy(id) if id.is_a?(Array) id.map { |one_id| destroy(one_id) } else find(id).destroy end end
destroyはidか、idのArrayしか受け取らない。
- Arrayだったら、繰り返して自分自身を呼ぶっぽいなー。
- Arrayじゃなければ、idでfindしたオブジェクトに対して、destoryを呼んでいる。
インスタンスのdestoryはどんな実装になってんだ。
def destroy unless new_record? connection.delete( "DELETE FROM #{self.class.quoted_table_name} " + "WHERE #{connection.quote_column_name(self.class.primary_key)} = #{quoted_id}", "#{self.class.name} Destroy" ) end @destroyed = true freeze end
- primary_keyとidを使って、deleteを呼んでいる、と。
SQL Injection出来そうなところはこれだけっぽい。
結論として、正しい使い方*2をしている限り、Injectionはできないっぽい。
エンコーディングが違う文字列を受け取るとまた違うのかな?