在activemodel关系上运行reduce时出现一个非常奇怪的错误。这似乎是在呼叫" c.name"在我的reduce代码中导致错误。 c.name返回字符串"俄罗斯联邦"。我使用reduce不正确吗?
这是错误:
[2014-03-17T21:12:40.174655 #9240] FATAL -- :
ActiveModel::MissingAttributeError (can't write unknown attribute `Russian Federation'):
app/controllers/registrations_controller.rb:96:in `block in pluck_countries'
app/controllers/registrations_controller.rb:96:in `pluck_countries'
来自控制台的更大堆栈跟踪:
@third_party_countries.reduce(@hsh) {|hsh, c| hsh[c.name] = ThirdPartyShipping.first }
ActiveModel::MissingAttributeError: can't write unknown attribute `Russian Federation'
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/activerecord-4.0.2/lib/active_record/attribute_methods/write.rb:47:in `write_attribute'
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/activerecord-4.0.2/lib/active_record/attribute_methods/dirty.rb:70:in `write_attribute'
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/activerecord-4.0.2/lib/active_record/attribute_methods.rb:341:in `[]='
from (irb):3:in `block in irb_binding'
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/activerecord-4.0.2/lib/active_record/relation/delegation.rb:63:in `each'
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/activerecord-4.0.2/lib/active_record/relation/delegation.rb:63:in `reduce'
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/activerecord-4.0.2/lib/active_record/relation/delegation.rb:63:in `method_missing'
from (irb):3
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/railties-4.0.2/lib/rails/commands/console.rb:90:in `start'
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/railties-4.0.2/lib/rails/commands/console.rb:9:in `start'
from /var/www/html/babiators.com/landf/vendor/bundle/ruby/2.0.0/gems/railties-4.0.2/lib/rails/commands.rb:62:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
以下是代码:
@third_party_countries = Country.third_party_countries
@hsh = HashWithIndifferentAccess.new
@third_party_countries.reduce(@hsh) {|hsh, c| hsh[c.name] = c.third_party_shipping }
国家架构:
create_table "countries", force: true do |t|
t.string "name"
t.float "shipping_rate"
t.integer "third_party_shipping_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "product_id"
end
国家模式:
class Country < ActiveRecord::Base
belongs_to :third_party_shipping
has_and_belongs_to_many :products
has_many :addresses
validates_presence_of :name
validates_uniqueness_of :name
before_create :init
after_initialize :init
scope :shippable, -> { where(third_party_shipping_id: nil) }
scope :third_party_countries, -> { where.not(third_party_shipping_id: nil) }
def shipping_price
self.shipping_rate * 100
end
def free_shipping
self.shipping_rate <= 0 and self.third_party_shipping_id.nil?
end
def paid_shipping
!self.free_shipping
end
def shipping_display
if self.free_shipping
"free"
elsif self.paid_shipping
self.shipping_rate
end
end
private
def init
if self.shipping_rate.blank?
self.shipping_rate = 0
end
end
end
答案 0 :(得分:0)
由于您在循环之外声明@hsh
,因此您无需inject
/ reduce
引入的额外复杂性。只需使用each
:
@hsh = HashWithIndifferentAccess.new
@third_party_countries.each{ |c| @hsh[c.name] = c.third_party_shipping }
现有代码的问题在于,使用inject
/ reduce
时,块的返回值将作为第一个参数传递给下一次调用。您需要从块中返回hsh
,否则c.third_party_shipping
的值将作为hsh
传递给下一次调用,并且您有效地执行c.third_party_shipping[c.name]
。< / p>
可以通过返回hsh
...
@third_party_countries.reduce(@hsh) do |hsh, c|
hsh[c.name] = c.third_party_shipping
hsh
end
但你不应该。您不需要此功能。 each_with_object
是正确的使用方法:
@hsh = @third_party_countries.each_with_object(HashWithIndifferentAccess.new) do |hsh, c|
hsh[c.name] = c.third_party_shipping
end
您也可以map
将数据集合@hsh = HashWithIndifferentAccess[@third_party_countries.map { |c| [c.name, c.third_party_shipping] }]
,并使用该数组初始化哈希:
[[a, b], [c, d]]
这依赖于在数组和散列之间自由转换的能力。数组{ a => b, c => d }
会转换为哈希{{1}}。