简体   繁体   中英

Rails has_one and belongs_to join

In my application I have models: Car:

class Car < ActiveRecord::Base
has_one :brand, through: :car_configuration
  has_one :model, through: :car_configuration
  has_one :body_style, through: :car_configuration
  has_one :car_class, through: :car_configuration

  belongs_to :car_configuration
end

CarConfiguration:

class CarConfiguration < ActiveRecord::Base
  belongs_to :model, class_name: 'CarModel'
  belongs_to :body_style, class_name: 'CarBodyStyle'
  belongs_to :car_class
  has_one :brand, through: :model
  has_many :cars, dependent: :destroy
  has_many :colors, dependent: :destroy
  def brand_id
    brand.try(:id)
  end
end

and CarBrand:

class CarBrand < ActiveRecord::Base
  default_scope { order(name: :asc) }
  validates :name, presence: true

  has_many :models, class_name: 'CarModel', foreign_key: 'brand_id'

end

Now I want to get all Cars which CarConfiguration brand id is for example 1. I tried something like this but this not work:

  joins(:car_configuration).where(car_configurations: {brand_id: 1})

Thanks in advance for any help.

Associations

I don't think you can have a belongs_to :through association ( belongs_to through associations ), and besides, your models look really bloated to me

I'd look at using a has_many :through association :

#app/models/brand.rb
Class Brand < ActiveRecord::Base
   has_many :cars
end

#app/models/car.rb
Class Car < ActiveRecord::Base
   #fields id | brand_id | name | other | car | attributes | created_at | updated_at
   belongs_to :brand

   has_many :configurations
   has_many :models, through: :configurations
   has_many :colors, through: :configurations
   has_many :body_styles, through: :configurations
end

#app/models/configuration.rb
Class Configuration < ActiveRecord::Base
   #id | car_id | body_style_id | model_id | detailed | configurations | created_at | updated_at
   belongs_to :car
   belongs_to :body_style
   belongs_to :model
end

#app/models/body_style.rb
Class BodyStyle < ActiveRecord::Base
   #fields id | body | style | options | created_at | updated_at
   has_many :configurations
   has_many :cars, through: :configurations
end 

etc

This will allow you to perform the following:

@car = Car.find 1
@car.colours.each do |colour|
   = colour
end

OOP

Something else to consider is the object-orientated nature of Ruby (& Rails).

Object orientated programming is not just a fancy buzzword - it's a core infrastructure element to your applications, and as such, you need to consider constructing your Models etc around objects:

在此处输入图片说明

This means that when you're creating your models to call the likes of Car objects, etc, you need to appreciate the associations you create should directly compliment that particular object

Your associations currently don't do this - they are very haphazard & mis-constructed. I would recommend examining what objects you wish to populate / create, and then create your application around them

In your achitecture, brand_id from CarConfiguration is not an attribute of the model hence, you can't query as you tried...

The solution is more to select the good car configuration first and get all the corresponding cars :

CarConfiguraton.joins(:brand).where(brand: {id: 1}).cars
    def self.with_proper_brand(car_brands_ids)
      ids = Array(car_brands_ids).reject(&:blank?)
      car_ids = Car.joins(:car_configuration).all.
        map{|x| x.id if ids.include?(x.brand.id.to_s)}.reject(&:blank?).uniq
      return where(nil) if ids.empty?

      where(id: car_ids)
    end

That was the answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM