how to connect two table that has no relation in rails - ruby-on-rails

I have a table called foods and categories, but this table has no relation, I want to connect them through another table called food_category. And I want to make one-to-one relation between food and category maybe the diagram looks like this
class Food < ApplicationRecord
has_one :category
end
class Category < ApplicationRecord
has_one :food
end
class FoodCategory < ApplicationRecord
belongs_to :category
belongs_to :food
end
Is it possible to do this?

Yes, this is possible. You just need to do
has_one :category, through: :food_categories
as discussed in the Rails docs here.
However, this is a long-winded way to go about this kind of association. If it's going to be one-to-one, why not just add a foreign key to Category from Food? And presumably, you would actually want Category to contain many Food records? Seems like the below would make more sense:
class Food < ApplicationRecord
belongs_to :category
end
class Category < ApplicationRecord
has_many :food
end

class Food < ApplicationRecord
has_one :food_category
has_one :category, through: :food_categories
end
In rails console, you can access like this
Food.find(:id).categories

Related

Matching the records in ruby on rails

I have a model company, which has association, has many candidates, and belongs to company.
And I have another model key_skill, which has association, has many key_skills, and belongs to candidate.
Another model is candidate, which belongs to company, and has many key skills association.
I am trying to get the candidate whose key skills are matched to the required skill and, it should search and get the candidate who belongs to the particular company.
How can I write a query in the model for this situation?
These are the associations
company.rb
class Company < ActiveRecord::Base
has_many :candidates
end
candidate.rb
class Candidate < ActiveRecord::Base
belongs_to :company
has_many :key_skills, dependent: :destroy
accepts_nested_attributes_for :key_skills, reject_if: :all_blank,
allow_destroy: true
end
key_skill.rb
class KeySkill < ActiveRecord::Base
belongs_to :candidate
end
I think your current association condition is like this:
class Company < ApplicationRecord
has_many :candidates
end
class Candidate < ApplicationRecord
belongs_to :company
has_many :key_skills
end
class KeySkill < ApplicationRecord
belongs_to :candidate
end
For example to fetch all candidates with key_skills with ids 1,2,3 run the following query
Candidate.joins(:company, :key_skills).where("key_skills.id in (?)", [1,2,3])
Try the below:
I am assuming that key_skills table have a field skill and you want to perform search on it.
candidate = Candidate.includes(:company, :key_skills).where("key_skills.skill like ?", "%#{params[:skill]}%")
company = candidate.company

Is: grandparent.parents.children association chaining not correct in Rails 4?

I'm having trouble figuring out the proper way of retrieving all children of multiple parents through association chaining.
To simplify I have three models:
class Customer < ActiveRecord::Base
has_many :invoices
end
class Invoice < ActiveRecord::Base
belongs_to :customer
has_many :line_items
end
class LineItem < ActiveRecord::Base
belongs_to :invoice
end
After creating a few objects I tired to use the example from rails guides (association basics: 4.3.3.4 includes):
Customer.first.invoices.line_items
It returns:
undefined method `line_items' for #<Customer::ActiveRecord_Associations_CollectionProxy
Is grandparent.parents.children not usable?
EDIT
I'm not searching for the grandparent.parents.first.children, but all children of all parents in the collection, rails guides state:
If you frequently retrieve line items directly from customers (#customer.orders.line_items),
As a valid operation, I would like to know if that is a mistake.
FINAL As stated in the comments of the selected answer: in ActiveRecord: scopes are chainable but associations are not.
The customer.invoices.line_items cannot work the way you want to, since the has_many always is linked to a single record. but you can achieve what you want (if I understand correctly) using has_many through
as follows:
class Customer < ActiveRecord::Base
has_many :invoices
has_many :line_items, through: :invoices
end
class Invoice < ActiveRecord::Base
belongs_to :customer
has_many :line_items
end
class LineItem < ActiveRecord::Base
belongs_to :invoice
end
and now you can write:
customer.line_items
and it will return all line_items which are connected to a customer's invoices.
Customer.first.invoices.first.line_items
Or if you want all of the data together, you can do something like:
results = Customer.first.invoices.includes(:line_items)
Then you may access data with no DB call, by looping results. For first data ex: results.first.line_items
Hope it helps!
Customer.first.invoices will return an collection (like an array) of invoices. The line_items method isn't defined for a collection, but its defined for an invoice. Try Customer.first.invoices.first.line_items
EDIT - If you always want the orders to include the line items, you can just do:
class Customer < ActiveRecord::Base
has_many :orders, -> { includes :line_items }
end
class Order < ActiveRecord::Base
belongs_to :customer
has_many :line_items
end
class LineItem < ActiveRecord::Base
belongs_to :order
end

How to create a Rent in Rails

I am tryng to develop a rent system where a user can login, create products, and his products can be rented by other users.
My problem is, I don't know how to create a rent that retrieves the product_id and customer_id. I made the relations but it isn't working.
I also create the CRUD for each one, even the rent. How can I store the information and pass to the Rent?
I have 4 models:
User
Product
Rent
Category
I created a new column in Rent called customer_id, and I've passed the class "User":
class Product < ActiveRecord::Base
belongs_to :user
belongs_to :category
belongs_to :rents
class User < ActiveRecord::Base
has_many :products
has_many :rents
has_many :customer_id, :through => :rent
class Rent < ActiveRecord::Base
belongs_to :user
belongs_to :product
belongs_to :customer, :class_name => "User"
end
I think I need to create a button that retrieves the information that I need. I searched through the documentation but I couldn't find it.
This line: has_many :customer_id, :through => :rent would never make sense this way in Rails. If you say has_many :customer_id, you are making two mistakes:
Whatever you write after has_many, it should be plural.
If what you write after has_many doesn't correspond directly to a model name as this the case with you, you have to explicit mention the class_name.
Same mistake you are repeating when you say:
class Product < ActiveRecord::Base
belongs_to :rents # it should be rent.
end
And now coming to what you are actually trying to implement:
class Rent < ActiveRecord::Base
belongs_to :user
has_one :product
has_one :customer
end
And in Product and Customer tables, you need to define rent_id as a foreign key. And you should also mention that each of them belongs_to Rent.

How to model table with items which have multiple subcategories?

I need some advice. I am pretty new in modeling database so I was wondering what would be the most convenient way to model database which would make my life easier. I have one Car item which can have multiple descriptive subcategories, like TireCategory, GlassCategory, EngineCategory...
I was thinking about doing something like this:
class Car < ActiveRecord::Base
belongs_to :tire_category
belongs_to :glass_category
belongs_to :engine_category
#Car would have three additional columns: tire_category_id, glass_category_id, engine_category_id
end
class TireCategory < ActiveRecord::Base
has_many :cars
end
class GlassCategory < ActiveRecord::Base
has_many :cars
end
class EngineCategory < ActiveRecord::Base
has_many :cars
end
Is this recommended way to do it or some other relation would be more suitable? Thank you!
You can store cars (with uniq data like model name and sku) in one table, properties (like engines, glasses) in another, and one more table for relation between cars and properties.
class Car < ActiveRecord::Base
has_many :car_properties, dependent: :destroy
has_many :properties, through: :car_properties
end
class Property < ActiveRecord::Base
has_many :car_properties, dependent: :destroy
has_many :cars, through: :car_properties
end
class CarProperty < ActiveRecord::Base
belongs_to :car
belongs_to :property
end
If you have a lot of properties and want to logically separate them then create separate models for each property. Like Engine, Tire, Glass. Each model will contain properties variants. Then create one table for each property to connect it to the car. Like CarEngine, CarGlass. It will contain car_id and property_id (engine_id, glass_id).

How to setup the associations for an "Options" model?

If had had the models Store, Product, User and Price with the following associations
class User < ActiveRecord::Base
has_many :products
has_many :stores
has_many :prices
end
class Store < ActiveRecord::Base
belongs_to :user
has_many :prices
end
class Product < ActiveRecord::Base
belongs_to :user
has_many :prices
end
class Price < ActiveRecord::Base
belongs_to :user
belongs_to :product
belongs_to :store
end
class Estate < ActiveRecord::Base
belongs_to :user
end
And want to create a Option model that holds the models specific option type with things like, if an Estate has a backyard, swimming pool, tennis court or a price has a deal, discount or buy one get one free. Would this be done by a polymorphic association?
I'm doing this so I don't have to create a Option model for each model and can just have one model for all new options I want to add. So is this the correct way to go about this?
If you use a polymorphic option model, then the fields would be the same for each class/record an object belongs to. I don't think this is what you want since a deal doesn't have a swimming pool and an estate isn't buy-one-get-one (I wish!).
I would look into using Rails 3.2 and the ActiveRecord::Store feature. With this, just add a single text column to your model(s) (call it "options") and then you can define all the options you need.
class Estate < ActiveRecord::Base
belongs_to :user
store :options, accessors: [ :backyard, :pool, :tennis, :butler, :wine_cellar ]
end
estate = Estate.new
estate.pool = true
estate.options[:number_of_sharks] = 3 # Attributes not defined as accessors work too

Resources