I have a User model, which has_many Dish through Recommendation. I would like to enforce uniqueness of Dish, as well as uniqueness of Recommendation.
How should I go about this in ActiveRecord?
In my dish.rb:
validate_uniqueness_of :dish_name
What I would like to have is: when an user recommends a dish, create a new dish if it does not exist, then create recommendation. If the dish already exists, then just create recommendation and point to existing dish.
Do I need to handle these situations manually (i.e., checking existence of dish in controller), or ActiveRecord has a way to handle it internally?
Update:
validate_uniqueness_of :dish_name only checks and return error message if the dish was created there. It probably won't create new recommendation that points to existing dish.
You could always .find_or_create_by_<attribute> to find the dish to begin with
As I see, more than one user can recommend the same dish.
Your models should look like:
Class User < ActiveRecord::Base
has_many :recommendations
has_many :dishes, :through => :recommendations
end
Class Dish < ActiveRecord::Base
has_many :recommendations
has_many :users, :through => :recommendations
end
So your Recommendations table in database should have two columns (beside it's id and timestamps) called user_id and dish_id . To validate that a user doesn't recommend
the same dish twice, do:
Class Recommendations < ActiveRecord::Base
belongs_to :dish
belongs_to :user
validates_uniqueness_of :dish_id, :scope => :user_id
end
And i didn't know about the .find_or_create_by method that Dan recommended, so definetly try to use something like that.
Hope i helped :)
Related
In my rails app, user's can create Designs.
Design.rb
belongs_to :user
User.rb
has_many :designs
I'm trying to create a new model Look so user's can create Looks. The way I envision this to work is when a user goes to /looks/new, they have a list of all the designs they have favorited (which I have that set up that variable already) in a table format with the right column being checkboxes where the user can go through and check a few of those Designs and click Create. All the Designs that have been checked would be part of that Look.
As I haven't done this sort of thing before, I need some help accomplishing this in all aspects MVC.
Look.rb
has_many :designs
Design.rb
belongs_to :looks # ??? Would the model be something different since technically when you create a design it doesn't belong to a look.
Looks Controller
def new
#designs = #user.favorites #This get's me all the designs that the particular user has favorited
#look = Look.new # ??? Again, as I haven't set this sort of relation up before, I'm unsure.
end
Please let me know any other code I can provide to help out. I may even be making this sound more complicated than it is.
This configuration should work for you Justin:
class User < ActiveRecord::Base
has_many :designs
has_many :looks, through: :designs
end
class Design < ActiveRecord::Base
belongs_to :user
has_many :designs_looks
has_many :looks, through: :designs_looks
end
class Look < ActiveRecord::Base
has_many :designs_looks
has_many :designs, through: :designs_looks
end
class DesignsLook < ActiveRecord::Base
belongs_to :design
belongs_to :look
validates :design_id, presence: true
validates :look_id, presence: true
end
I don't know what you want to do in the future but you might want to consider putting the user_id on the DesignsLook model, so you would not need a complex join query to retrieve all the Looks of a User. And also you implement shared Designs with all users
Your user has many designs. New looks can have many designs. And design can belong to MANY looks, users. Smells like has many ..., :through
http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
class User
has_many :designs, through: :design_possesion
end
class Look
has_many :designs, through: :look_designs
end
class Design
has_many :look_designs, :design_possesion
end
Of course you'll have to create corresponding tables.
I am currently trying to set up a model structure that seems quite simple, but I haven't quite got it down.
I have a model payment that can belong to either a customer or a supplier (which can both have many payments).
My question is simply whether I need to manually create an interface table to allow this, or if declaring the polymorphic associations will do this for me?
e.g. I have:
class Payment < ActiveRecord::Base
belongs_to :payment_originator, :polymorphic => true
end
class Customer < ActiveRecord::Base
has_many :payments, :as => :payment_originator
end
class Supplier < ActiveRecord::Base
has_many :payments, :as => :payment_originator
end
Is this enough, or do I also need to use a generator to manually create the payment_originator model?
Thanks!
As far as the models go, this is good enough. You just need to migrate a :payment_originator_type and :payment_originator_id to the payments table. The associations you defined above will automatically fill these in for you.
I am trying to create an association between two tables. A student table and a computer table.
A computer can only ever be assigned to one student (at any one time) but a student can be assigned to multiple computers.
This is what I currently have in mind. Setting up a has-many through relationship and modifying it a bit.
class Student < ActiveRecord::Base
has_many :assignemnts
has_many :computers, :through => :assignments
end
class Computer < ActiveRecord::Base
has_one :assignment
has_one :student, :through => :assignments
end
class Assignment < ActiveRecord::Base
belongs_to :student
belongs_to :computer
end
Does this seem like the best way to handle this problem? Or something better sound out quickly to the experts here. Thanks!
You need first to decide if a simple one-to many relationship is enough for you.
If yes, it gets a lot easier, because you can get rid of the Assignment-class and table.
Your database-table "computers" then needs a student_id column, with a non-unique index
Your models should look like this:
class Computer < ActiveRecord::Base
belongs_to :student
end
class Student < ActiveRecord::Base
has_many :computers, :dependent => :nullify
end
"dependent nullify" because you don't want to delete a computer when a student is deleted, but instead mark it as free.
Each of your computers can only be assigned to a single student, but you can reassign it to a different student, for example in the next year.
Actually your approach is fine, as one offered by #alexkv. It is more discussion, than question.
Another thing if you want to use mapping table for some other purposes, like storing additional fields - then your approach is the best thing. In has_many :through table for the join model has a primary key and can contain attributes just like any other model.
From api.rubyonrails.org:
Choosing which way to build a many-to-many relationship is not always
simple. If you need to work with the relationship model as its own
entity, use has_many :through. Use has_and_belongs_to_many when
working with legacy schemas or when you never work directly with the
relationship itself.
I can advise you read this, to understand what approach better to choose in your situation:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
http://blog.hasmanythrough.com/2006/4/20/many-to-many-dance-off
You can also use has_and_belongs_to_many method. In your case it will be:
class Student < ActiveRecord::Base
has_many :assignemnts
has_and_belongs_to_many :computers, :join_table => 'assignments',
end
class Computer < ActiveRecord::Base
has_one :assignment
has_and_belongs_to_many :student, :join_table => 'assignments',
end
or you can rename assignments table to computers_students and remove join_table
class Student < ActiveRecord::Base
has_many :assignemnts
has_and_belongs_to_many :computers
end
class Computer < ActiveRecord::Base
has_one :assignment
has_and_belongs_to_many :student
end
I am trying building a simple project from scratch using Rails 3. Usually, the models are like:
class Student < ActiveRecord::Base
has_many :awards
end
class Award < ActiveRecord::Base
belongs_to :student
end
and we use the award.id and student.id to get the corresponding records.
But what if it is
class Company < ActiveRecord::Base
has_many :stock_quotes
end
class StockQuote < ActiveRecord::Base
belong_to :company
end
In this case, we can use the symbol of the company, such as MSFT or GOOG to identify the company, instead of using the company.id. For example, in stock_quotes, we can store the symbol of the company directly instead of using company.id. In this case, is there a way to specify it in the models?
http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/belongs_to
http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_many
Check out :primary_key and :foreign_key options
In addition to Slawosz' answer, this question about non-integer primary keys is also relevant to your question. IMHO, it would be easier to just use integer id's like in the example of Award and Student.
Slawosz has the answer right. To be verbose (and for the next time I search this) it should be like this:
#company
has_many :stock_quotes, :primary_key => :symbol
#stock_quote
belongs_to :company, :foreign_key => :symbol
My situation is like this.
Company has many users and users may belongs to many companies.
And current implementation is something like below.
class Company
has_many :employments
has_many :users, :through => :employments
end
class Employment
belongs_to :company
belongs_to :user
end
class User
has_many :employments
has_many :companies, :through => :employments #This doesn't looks correct
end
It works, but "user has many companies" doesn't looks logically meaningful. It must be some thing like belongs_to_many companies.
Do I need to use has_and_belongs_to_many?
Can some one please suggest the right way for representing these relationships?
If you are not going to add some special behaviour to Employment class and you don't really need it, then you should propably better use has_and_belongs_to_many. This way it will still have some table called CompanyUser, but there will not be any such class in the code.
Added:
There are just 3 possbile conections between 2 objects: 1-to-1, 1-to-many and many-to-many. Rails indicates with has_* or belongs_to what of the 2 objects will get a foreign key. So:
1-to-1:
has_one and belongs_to are used. The object with belongs_to gets the FK.
1-to-many:
has_many and belongs_to are used. The object with belongs_to gets the FK.
many-to-many:
has_many[through] or has_and_belongs_to_many are used in both objects. No-one gets a FK, instead a ConnectionTable is used.
So there is no such thing as belongs_to_many, because it would be the same as has_many - providing the same relation 1-to-many.