2

Railsのメカニズムを完全に誤解しました...多くの特性を持つ製品モデルを想像してみてください。

class Product < ActiveRecord::Base
    has_many :properties
end

次に、コンソールで次のように入力します。

p=Product.last #recover the last product created
arr=p.properties #return the properties in an Array
arr.class #return "Array", so it's effectively an Array object.

Hirbではそれは私に与えます:

1.9.3-p385 :161 > arr=p.properties
| id        | name        | presentation  | created_at              | updated_at              | value_type |
+-----------+-------------+---------------+-------------------------+-------------------------+------------+
| 905834907 | internet    | internet      | 2012-09-17 13:37:57 UTC | 2012-10-02 15:46:37 UTC | boolean    |
| 905834906 | three_d     | 3D            | 2012-09-17 13:37:47 UTC | 2012-10-10 13:10:07 UTC | boolean    |
| 161337574 | brand       | Marque        | 2012-05-22 14:13:04 UTC | 2013-03-26 16:12:12 UTC | string     |

等...

次に、私がそうする場合:

1.9.3-p385 :162 > arr.where(:value_type => "boolean")
  Spree::Property Load (0.8ms)  SELECT "spree_properties".* FROM "spree_properties" INNER JOIN "spree_product_properties" ON "spree_properties"."id" = "spree_product_properties"."property_id" WHERE "spree_product_properties"."product_id" = 1060500665 AND "spree_properties"."value_type" = 'boolean'
+-----------+----------+--------------+-------------------------+-------------------------+------------+
| id        | name     | presentation | created_at              | updated_at              | value_type |
+-----------+----------+--------------+-------------------------+-------------------------+------------+
| 905834907 | internet | internet     | 2012-09-17 13:37:57 UTC | 2012-10-02 15:46:37 UTC | boolean    |
| 905834906 | three_d  | 3D           | 2012-09-17 13:37:47 UTC | 2012-10-10 13:10:07 UTC | boolean    |
| 905834914 | wifi     | wifi         | 2013-03-26 16:13:35 UTC | 2013-03-26 16:13:35 UTC | boolean    |

だから私は配列でwhereメソッドを実行します...しかし:

tab.method(:where) #returns:
NameError: undefined method `where' for class `Array'

それを認識しないオブジェクトのどこを実行するにはどうすればよいですか?私はある種の考えを持っています:

1.9.3-p385 :164 > arr.klass
 => Spree::Property(id: integer, name: string, presentation: string, created_at: datetime, updated_at: datetime, value_type: string) 

しかし、私はそのメカニズムを本当に理解していません...それはオブジェクト指向言語ではまったく新しいものです。

説明ありがとうございます。

PH

4

2 に答える 2

0

良い質問!

コンソールの動作は少し誤解を招く可能性があります。

p=Product.last #recover the last product created
arr=p.properties #return the properties in an Array
arr.class #return "Array", so it's effectively an Array object.

arr.classコンソールactiverecordがプログラマーとしてあなたを助けたいので、「配列」を返します。したがって、のarr.all.class代わりに実行しarr.classます。

を実行するarr.to_sqlと、SQLが生成されることがわかります。Arrayオブジェクトにはメソッドがありませんto_sql

where(:value_type => "boolean")遅延読み込みのため、メソッドとして使用できますarr

遅延読み込みの詳細については、http://xyzpub.com/en/ruby-on-rails/3.2/queries.html#lazy_loadingをご覧ください

于 2013-03-27T11:36:57.640 に答える
0

重要なのは、実際にはのインスタンスではArrayなく、のインスタンスを取得することですActiveRecord::Relation。これは、これらすべてのディレクティブをチェーン化できるようにするためであり、結果にアクセスしようとすると、基になるリレーションが実行され、配列に変換されます。Pryは自動的に結果を表示しようとするため、これらの変換がトリガーされます。

あなたはこのようなことをすることによってそれを見ることができます:

[1] pry(main)> Customer.first.contracts ; nil
  Customer Load (0.6ms)  SELECT `customers`.* FROM `customers` LIMIT 1
=> nil

[2] pry(main)> Customer.first.contracts
  Customer Load (0.5ms)  SELECT `customers`.* FROM `customers` LIMIT 1
  Contract Load (0.7ms)  SELECT `contracts`.* FROM `contracts` WHERE `contracts`.`customer_id` = 1
=> [...results...]

[3] pry(main)> class ActiveRecord::Relation
[3] pry(main)*   def to_a
[3] pry(main)*     puts "I converted me (#{(class << self ; self ; end).superclass}) to an Array"
[3] pry(main)*     logging_query_plan do
[3] pry(main)*       exec_queries
[3] pry(main)*     end
[3] pry(main)*   end
[3] pry(main)* end
=> nil

[4] pry(main)> Customer.first.contracts ; nil
I converted me (ActiveRecord::Relation) to an Array
  Customer Load (0.5ms)  SELECT `customers`.* FROM `customers` LIMIT 1
=> nil

[5] pry(main)> Customer.first.contracts
I converted me (ActiveRecord::Relation) to an Array
  Customer Load (0.6ms)  SELECT `customers`.* FROM `customers` LIMIT 1
I converted me (ActiveRecord::Relation) to an Array
  Contract Load (0.6ms)  SELECT `contracts`.* FROM `contracts` WHERE `contracts`.`customer_id` = 1
=> [...results...]

ステップ[1]:のみCustomerがフェッチされます。contractsPryはそれにアクセスしようとしないため、-relationは実行されないままになります; nil

ステップ[2]: 1と同じですが、Pryはリレーションにアクセスしようとするため、それらもフェッチします。

ステップ[3]: ActiveRecord::Relation.to_aメソッドをオーバーライドします。puts残りは元のメソッドのみを追加しました(superを使用するとループが発生します!)。

ステップ[4]: 1.と2を繰り返します。各変換で追加のメッセージがトリガーされるようになりました。

Rubyでのメタプログラミングはかなり複雑で、多くの頭痛の種を引き起こしますが、これが物事を明確にすることを願っています。

于 2013-03-27T12:05:57.660 に答える