rails4 has_one与查询位置的关联范围

时间:2016-10-06 01:14:20

标签: ruby-on-rails ruby-on-rails-4 scope associations has-one

我正在开发一个产品模型,该模型与自身具有has_one关联,包括原材料记录。模型通过REST API返回数据。我使用的是Active Model Serializer而不是JBuilder。

产品型号有一个'代码'包含字符串中的产品代码的字段:

StatusCode

只有两个代码之间的差异是右起第三个数字。 ' 1'是产品。 ' 0'是物质的。我想要包含一个" raw_material"检索产品记录时记录。所以,我尝试将has_one关联设置为具有"其中"子句(稍后我可以撰写查询以从产品代码中获取材料)。现在我只是通过" product" lambda中的对象并在其中使用它。

首先我在def raw_material中写道,这是有效的。但是,我不知道如何将对象传递给def并在where子句中使用它。因此,我在has_one中提出了范围模式,但即使它生成与def模式完全相同的SELECT,它也会返回错误。我得到了#No; NoMethodError"代替。

'001-000-01-01' (This is a product.)
'001-000-00-01' (This is a material.)

" def"模式有效:

class Product < ActiveRecord::Base
  has_many :supplies, ->{order('row_order ASC') }, primary_key: :code, foreign_key: :product_code
  #This Works!
  #has_one :raw_material, class_name: 'Product', primary_key: :code, foreign_key: :code
  #This Works!
  #has_one :raw_material
  #Does not work. Why?
  has_one :raw_material, ->(product) { where('code = ?', product.code).take }, class_name: 'Product'
  accepts_nested_attributes_for :supplies, allow_destroy: true

  #def raw_material
  #  Product.where('code = ?', '001-000-01-01').take
  #end
end

但是,范围模式不起作用:

Started GET "/products/1.json" for ::1 at 2016-10-05 21:48:15 +0900
Processing by ProductsController#show as JSON
  Parameters: {"id"=>"1"}
  Product Load (0.3ms)  SELECT  "products".* FROM "products" WHERE "products"."id" = ? LIMIT 1  [["id", 1]]
[active_model_serializers]   Supply Load (0.1ms)  SELECT "supplies".* FROM "supplies" WHERE "supplies"."product_code" = ?  ORDER BY row_order ASC  [["product_code", "031-052-00-01"]]
[active_model_serializers]   Product Load (0.1ms)  SELECT  "products".* FROM "products" WHERE (code = '001-000-01-01') LIMIT 1
[active_model_serializers] Rendered ProductSerializer with ActiveModelSerializers::Adapter::Attributes (6.71ms)
Completed 200 OK in 24ms (Views: 9.2ms | ActiveRecord: 1.4ms)

Product Controller只是定义了这样的节目:

Started GET "/products/1.json" for ::1 at 2016-10-06 08:19:13 +0900
Processing by ProductsController#show as JSON
  Parameters: {"id"=>"1"}
  Product Load (0.1ms)  SELECT  "products".* FROM "products" WHERE "products"."id" = ? LIMIT 1  [["id", 1]]
[active_model_serializers]   Supply Load (0.1ms)  SELECT "supplies".* FROM "supplies" WHERE "supplies"."product_code" = ?  ORDER BY row_order ASC  [["product_code", "031-052-00-01"]]
[active_model_serializers]   Product Load (0.1ms)  SELECT  "products".* FROM "products" WHERE (code = '031-052-00-01') LIMIT 1
[active_model_serializers] Rendered ProductSerializer with ActiveModelSerializers::Adapter::Attributes (10.6ms)
Completed 500 Internal Server Error in 27ms (ActiveRecord: 1.2ms)

NoMethodError (undefined method `except' for #<Product:0x007fe97b090418>):
  app/controllers/products_controller.rb:17:in `block (2 levels) in show'
  app/controllers/products_controller.rb:14:in `show'


  Rendered vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.5/lib/action_dispatch/middleware/templates/rescues/_source.erb (8.8ms)

product_serializer.rb是:

# GET /products/1
# GET /products/1.json
def show
  respond_to do |format|
    format.html
    format.json do
      render json: @product, include: ['raw_material']
    end
  end
end 

非常感谢任何帮助。

谢谢

更新

我自己解决了这个问题。请检查下面的答案。感谢所有撰写解决方案的人。

3 个答案:

答案 0 :(得分:0)

 # Does not work. Why?
 has_one :raw_material ->(product) { where('code = ?', product.code).take }...

因为你试图在这里定义一个范围......而不是一个关联。如果你想要一个范围,请使用范围,例如:

scope :raw_material ->(product) { where('code = ?', product.code).first }

如果您想要关联,请使用关联,例如

has_one :raw_material, class_name: 'Product', primary_key: :code, foreign_key: :code
不要试图将两者混合在一起。

答案 1 :(得分:0)

您可以按如下方式自定义has_one:raw_material。

class ProductSerializer < ActiveModel::Serializer
  attributes(*Product.attribute_names.map(&:to_sym))

  has_one :raw_material do
    Product.where(code: object.code)
  end

end

答案 2 :(得分:0)

我自己可以解决这个问题。因为我不必在一行中写这个,所以def(方法)模式是最好的选择。如何覆盖“has_many”可以帮助我解决问题。

Overriding a has_many association getter

“self”可用于has_one以获取def中的对象。

has_one :raw_material

def raw_material
  Product.where('code like ?', (self.code)[0,9] + '_' + (self.code)[10,3]).take
end

这样可以在模型中生成您喜欢的任何数据集。