I have two two models: Company and CompanyType. I need an association setup where a company can have and belong to many types. Based off the rails convention of naming join models I'm in sort've a bind. I can't name my join model CompanyType because that obviously exists. What do you do in these sort've situations?
class Company < ApplicationRecord
end
class CompanyType < ApplicationRecord
end
If you are not going to attach more stuff to it, you can skip creating the join model by defining a has_and_belongs_to_many association:
class Company < ApplicationRecord
has_and_belongs_to_many :company_types
end
class CompanyType < ApplicationRecord
has_and_belongs_to_many :companies
end
# No join model needed
You still need a migration to create the table though. See: http://apidock.com/rails/v4.2.1/ActiveRecord/Associations/ClassMethods/has_and_belongs_to_many
If you need the join model, you can follow the method explained in the same document, I guess.
Related
My model setup
class User < AR
has_many :books
...
end
class Book < AR
belongs_to :user
...
end
Books are in separate apartments and users are in the public schema.
I would like to add a shared model called assignment (to assign a book to a user) in the public schema that will have the following setup
class User < AR
has_many :books
has_many :assignments
...
end
class Book < AR
belongs_to :user
has_one :assignment
...
end
class Assignment < AR
belongs_to :user
belongs_to :book
...
end
The problem lies with the belongs_to :book portion in that the Assignment model is shared, giving no way to easily specify the schema that the book is in. There is also the possibility of id collisions among the books across different schemas which complicates the process further. As I see it I could:
1) Use scopes, specifying the apartment schema for the book
2) Use custom getters and setters for the book attribute in assignment, and fetch the required objects in the getter.
3) Put the assignment foreign key in the books model, which would be the simplest but not as clean (I want to be able to get the book_id/schema without a join)
4) Distribute the assignments model to the apartment schemas, which would be difficult as I must collect the assignments and sync them to an outside data source.
What is the best solution in this situation?
Lets say I have a STI model called Company. It has three sub-classes Firm, Client and PriorityClient.
class Company < ActiveRecord::Base
scope :firms_n_clients, -> { where(type: %w(Firm Client)) }
end
class Firm < Company; end
class Client < Company; end
class PriorityClient < Company; end
I have another model called Country. Now I want to create a has_and_belongs_to_many association between Country and firms_n_clients(only Firm and Client type of Company). How would it be?
Thanks in advance.
has_and_belongs_to_many associations accept scopes. Some of them are discussed in the Ruby on Rails documentation. Assuming the necessary join table exists, the association can be established like so:
class Country < ActiveRecord::Base
has_and_belongs_to_many :companies, -> { where(type: %w(Firm Client)) }
end
class Firm < Company
has_and_belongs_to_many :countries
end
class Client < Company
has_and_belongs_to_many :countries
end
Please note the duplicate Code in Client and Firm. This is on purpose, because it reveals explicitly that Clients and Firms have and belong to countries, and PriorityClients do not.
I have not tested the below code, but an even better way to modify the HABTM Association would be to merge the the firms_n_clients scope:
class Country < ActiveRecord::Base
has_and_belongs_to_many :companies, -> { merge(Company.firms_n_clients) }
end
This has several advantages: The Country model doesn't need to know about the different Company types, and modifying the scope will affect the association as well.
I have many to many relation between users and projects through user_project. I know I could simply add has_many :projects in User Serializer (and vice versa in project serializer) to nest projects inside users.
But I also have a few additional fields in user_projects table (eg. start and end dates for user's participation in a corresponding project) and I have no idea what is the correct way to include them in the returned json. Should I create a special serializer for projects that are returned inside user with start_date included as a project's attribute or there's another way to do that?
The best way to do this would be to establish a 'has-many-through' (HMT) relationship between the user and project models and create a serializer for relationship's model.
class UserProjectSerializer < ActiveModel::Serializer
...
end
This will then be used in the UserSerializer via:
has_many :users_projects
The reason is that the relationship between the models contains additional data.
To implement the HMT, you'll need to create the user_projects model and define the HMT relationship in the related models:
users_project.rb
class UserProjects < ActiveRecord::Base
belongs_to :user
belongs_to :project
end
user.rb
class User < ActiveRecord::Base
has_many: users_projects
has_many: projects, through: :user_projects
end
project.rb
class Project < ActiveRecord::Base
has_many: users_projects
has_many: users, through: :user_projects
end
I have had a similar problem before and I made use of rabl. There is a good tutorial on railscasts to help you get started.
I have a question with Rails 3.1 associations. When you have a one-to-many association you put the has_many operators on the many side of the relationship and the usual example does something like this:
class Order < ActiveRecord::Base
belongs_to :customer
end
class Customer < ActiveRecord::Base
has_many :orders
end
My question is how should I do this if the class name is Orders? Should I put has_many :orders or should I always name my models using singular nouns?
Rails convention states that model names should always be singular, so you should never have a model class named Orders; it would probably just be Order.
I am trying to model a publications. A publication can have multiple authors and editors. Since it is possible that one person is an author of one publication and an editor of another, no separate models for Authors and Editors:
class Publication < ActiveRecord::Base
has_and_belongs_to_many :authors, :class_name=>'Person'
has_and_belongs_to_many :editors, :class_name=>'Person'
end
The above code doesn't work, because it uses the same join table. Now I now that I can specify the name of the join table, but there is a warning in the API documentation is a warning about that which I don't understand:
:join_table:
Specify the name of the join table if the default based on lexical order
isn’t what you want. WARNING: If
you’re overwriting the table name of
either class, the table_name method
MUST be declared underneath any
has_and_belongs_to_many declaration in
order to work.
It means that if class Publication is linked to a table with no standard name, example "my_publications":
class Publication < ActiveRecord::Base
set_table_name "my_publication"
end
The set table name should be put behind the habtm declaration for this to work:
class Publication < ActiveRecord::Base
has_and_belongs_to_many :authors, :class_name=>'Person'
has_and_belongs_to_many :editors, :class_name=>'Person'
set_table_name "my_publication"
end
I'd generally consider this a case where you want to use has_many :through.