2012-03-06 2 views
15

レッツモデルを使用して別のオブジェクトから属性をコピーする[price, description]のRails:「属性」メソッドの属性を持っている<code>Quote</code>

[price, description, priority]

を属性を持つInvoice

レッツモデルはinvoice属性を持つモデルInvoiceからオブジェクトをしてみましょう{price: 10, description: 'lamp', priority: 10}

invoice = {price: 10, description: 'lamp', priority: 10} 

たとえば、invoiceの属性を新しいにコピーしたいとします。

quote = Quote.new(invoice.attributes) 

これはpriorityは、モデルQuoteにexisteしないこと、エラーが発生します。

属性quoteにはinvoiceの属性をコピーできますが、quoteの属性は受け入れることができますか?

答えて

19

あなたはQuoteが持っているselect属性のみ行うことができます

Quote.new(invoice.attributes.select{ |key, _| Quote.attribute_names.include? key }) 

As noted by @aceofspades(ただし、動的な溶液で)、あなたにもactivesupportののsliceを使用することができます。

Quote.new(invoice.attributes.slice(*Quote.attribute_names)) 
+0

すべて 'attribute_names'はかかわらず、コピーする必要がありません。 'id'、' updated_at'と 'created_at'はインスタンス化時にはおそらく' nil'でなければなりません。 – Mischa

+3

配列だけを渡すと{}が返されます。 Quote.new(invoice.attributes.slice(* Quote.attribute_names)) – Ajay

+0

@ajayこんにちは、あなたの答えは本当に役に立ちます。複数の属性を追加する場合と同じシナリオがあります。そこで私は '未定義のメソッド属性'というエラーを受け取りました。どうすれば修正できますか?ありがとう – Learner

0

簡単な方法がありますこのようなもの:

source = invoice.attributes 
target = (source.keys & Quote.attribute_names).inject({}) {|target, key| target[key] = source[key]; target } 
quote = Quote.new(target) 
12

ActiveSupportのスライス方法はどうですか?

quote = Quote.new(invoice.attributes.slice(:price, :description)) 

あるいは

quote = Quote.new(invoice.attributes.slice(*Quote.accessible_attributes)) 
+0

'accessible_attributes'は奇妙な振る舞いをしているようですが、' attr_accessible'で明示的に指定された属性だけを返すので、デフォルトでは属性は含まれません。これは、私にとって、Railsのバグです。 –

+0

attr_accessibleは本当に良いアイデアです。あなたの答えにはattribute_namesも同様に機能します。 – aceofspades

+0

私はあなたが*すべきことを知っています*しかし、それは人々が(日曜日に証明されたように)行うことを意味しません。それは、明示的にマークされているものだけでなく、すべてのアクセシブルな属性を返すことを期待していると言いました。 –

関連する問題