ActiveRecords [something] belongs_to [User] and has_many [Users] - ruby-on-rails

I'm modelling a scenario with Users and Tools, where a Tool is owned by one User but can be used by many Users including to one owning it.
I was thinking about adding an owner_id column to Tools and say it has_many Users or by adding a new relationsship table.
I'm really new to Rails and I have problems setting up the right associations in the models though, maybe you can point me in the right direction?
Thank you very much.

Your should add owner_id to the Tools table.
Associations will be like that.
class User < ActiveRecord::Base
has_and_belongs_to_many :tools
end
class Tool < ActiveRecord::Base
has_and_belongs_to_many :users
belongs_to :owner, :class_name => 'User'
end
You'll need a tools_users table in order to use habtm-association. Generate a migration and create a table with option id: false and two columns user_id and tool_id:
class CreateToolsUsersTable < ActiveRecordMigration
def change
create_table :tools_users, id: false do |t|
t.integer :tool_id
t.integer :user_id
end
end
end
After that you can call something like #user.tools or #user.owner
Read more there

User has many tools
Tool belongs to user in owner
Tool has many users
is what I would do.
I'm not sure about the wording because I don't use Active Record but this is how it works in other orms

Related

Rails belongs_to one of two models

I'm working with two different models Person and Organization. Among many other attributes, both a Person and Organization can be a Contractor. If I was working with just the Person model and wanted to store contractor information I would say that Contractor belongs_to :person and be done with it. However this seems like Contractor belongs to two other models.
I searched around on google and found a lot of info about how to assign ownership to two different models at once. (For example a Sale must belong to both a Buyer and a Seller.) But in my situation a Contractor is EITHER a Person or an Organization. Is there any way to elegantly store Contractor information for both models in the same table?
If not, I figure I can always make two different contractor tables, but I figured this might be an opportunity to learn something. Many thanks in advance.
Maybe you can try this. Rails provide polymorphic-associtions. You can try to build one model named ContractorInfo belongs to Contractable(use polymorphic: true), then Person has_one ContractorInfo as contractable, Organization has_one ContractorInfo as Contractable.
I agree with ShallmentMo, but as additional, You could define something like this:
Models
class Contractor < ActiveRecord::Base
belongs_to :contractable, polymorphic: true
...
end
class Person < ActiveRecord::Base
...
has_many :contractors, as: :contractable
...
end
class Organization < ActiveRecord::Base
...
has_many :contractors, as: :contractable
...
end
Migrations
create_table :contractors , force: true do |t|
t.references :contractable, polymorphic: true, index: true
...
t.timestamps null: false
end
Usage
def create
#contractor = Contractor.new(params[:contractor])
contractable = params[:contractor][:contractable].split(":")
#contractor.contractable_type = contractable[0] # String: 'Person' or 'Organization'
#contractor.contractable_id = contractable[1].to_i # Integer: id of 'Person' or 'Organization'
...

How to deal with different type of users with rails?

I need to know, if there is a way to deal with different type of users/clients in Rails using a single model.
What I really need to do?
- I need to save a different type of clients in my database. So, I have this migration:
class CreateClients < ActiveRecord::Migration
def change
create_table :clients do |t|
t.string :name # Person name if "Personal", Company name if type "Company"
t.string :nif # fillable only if type is Company
t.string :identity_card_number # fillable only if type is Personal
t.integer :client_type # Type can be Personal or Company
t.references :company, index: true # if type is personal, it can belong to a company
t.timestamps null: false
end
end
end
Then I create this model
class Client < ActiveRecord::Base
has_many :employees, class_name: 'Client', foreign_key: 'company_id'
belongs_to :company, class_name: 'Client'
end
Note: A personal account can belong to a company or not.
Based on your experience, am I doing this in the right way? There are another way to do that?
EDIT:
Hi #manfergo25,
Whit this I have another question. "Company" and "Personal" are both "Clients Account", in that way, both must be able to buy services.
If I need to associent the client with the service, can I do this?
class Personal < Account
has_many :services
end
and
class Service < ...
belongs_to :account
end
??
The right way is Single Table Inheritance (STI) as Sontya say.
class Account < ActiveRecord::Base
end
Then,
class Client < Account
end
class Provider < Account
end
You only have to add a type column in 'Account' to contain a string representing the type of the stored object.
For example in a controller you could do this:
account = Client.find(params[:autocomplete_client])
params[:service][:account_id] = account.id
#service = Service.new(params[:service])
You can use STI(Single Table Inheritance)
class Account < ActiveRecord::Base
end
class Company < Account
has_many :services, :dependent => :destroy
end
class Personal < Account
has_many :services, :dependent => :destroy
end
class Service < ActiveRecord::Base
belongs_to: personal
belongs_to: company
end
With the above definition, a personal and company should be able to buy services.
and you should be able to call
#company.services # it will return you the number of services of company
#personal.services # it will return you the number of services of personal
Personally, I think the way you have suggested in your question is the way I'd do it.
While Single Table Inheritance is intellectually better modelling -- I've found STI to be a bit hard to work with and sometimes unreliable in Rails. And probably won't improve the cleanliness or conciseness of your code all that much in the end anyway. STI is good to keep in mind as an option, if you find the OP approach is not working well as far as allowing you to write clear concise code and it seems STI could work out better.
But I'd start without STI, with just the one Client class, as you've outlined in your question. If you later add STI, you'd still have the Client class, you'd just have sub-classes for, say, PersonalClient and CompanyClient. It won't be that hard to switch to STI later if you want to, although it might require some minor db schema alterations.
But I don't think it'll get you enough benefit to justify the added complexity, in an area of Rails that has sometimes had some rough edges.
Here's some more info about STI and it's plusses and minuses: http://eewang.github.io/blog/2013/03/12/how-and-when-to-use-single-table-inheritance-in-rails/

Multiple relationships between two models in rails

I have a comment system with two tables: comments, and users. On the comment I want to record who the author was and also I want to notify any user that is mentioned in the comment with (#username). So I'm thinking I need to have an author_id on the comment, and also a comments_users table with the comment id and all the users ids that were mentioned. Would this be a correct way to accomplish it?:
User:
has_many :comments
Comment:
belongs_to :users, class_name: 'User', foreign_key: 'author_id'
has_many :users
The associations could be set up thus:
#app/models/user.rb
Class User < ActiveRecord::Base
has_many :comments
has_and_belongs_to_many :mentions, join_table: "comments_users", association_foriegn_key: "comment_id"
end
Class Comment < ActiveRecord::Base
belongs_to :author, class_name: "User", foreign_key: "author_id"
has_and_belongs_to_many :mentions, join_table: "comments_users", foreign_key: "comment_id"
end
#comments_users
comment_id | user_id
This will allow you to call:
#user.comments #-> shows comments user has authored
#user.mentions.first.comment #-> shows first comment user was mentioned in
#comment.author #-> shows user who authored comment
#comment.mentions.first.user #-> shows first user who was mentioned in comment
Update
HABTM still needs a table (Rails migration for has_and_belongs_to_many join table), but the difference is that it doesn't need a primary key column (just comment_id | user_id)
We've created a "self-referential" habtm relationship, meaning you don't need to "create" any records -- they should all be created already. The HABTM will just reference them. As such, you'll need to use the << ActiveRecord method to add records into your mentions collection:
#app/controllers/comments_controller.rb
Class CommentsController < ActiveRecord::Base
def create
#comment = Comment.new(comments_params)
#comment.save_with_mentions
end
end
#app/models/comment.rb
Class Comment < ActiveRecord::Base
def save_with_mentions
comment = self.save
#do something to find mentioned users
mentioned_users = User.where("user_id = 1") #example
for user in mentioned_users do
comment.mentions << user
end
end
end
There are always many ways to accomplish any given task, but I'm guessing you're looking for something like this for your models & associations.
User:
has_many :comments
The user model association looked right.
Comment:
belongs_to :author, class_name: 'User', foreign_key: 'user_id'
has_many :users
Note, the belongs_to should reference a model in singular-naming style (ie: user vs users). I think you're going to want to do a reference like comment.author to find the author of your comments. It is more typical to provide a foreign_key of user_id when referring to a User model to keep things clear, but then provide a clarifying association name like "author" or "creator" or whatever for reference as I showed above. So your Comments table would have a foreign_key of user_id to reference back to the Users table. This user would be referenced in Rails by the name "author".
The second part of your question that has to do with tracking other user references in your model sounds like a one-to-many from the comment-users table. So, that sounds like one option. Similar to your "author" comment, you may want to provide a clearer name like "tags" which can just be references to users.
Another good option for this feature may be to set up a polymorphic table (essentially a flexible join table) if you plan to use this principle elsewhere in your app (like for referencing/tagging people in other elements like a photo or posting or something). It could provide greater flexibility for adding features and tracking these user references. A polymorphic table could have any name, but usually has an "-able" type name - like "taggable". Here's a useful reference: http://guides.rubyonrails.org/association_basics.html#polymorphic-associations

many to many relationship in rails 3

I have created 2 models in rails and modified the models classes to add a many to many relationship (with has_and_belongs_to_many)
class User < ActiveRecord::Base
has_and_belongs_to_many :categories
end
class Category < ActiveRecord::Base
has_and_belongs_to_many :users
end
When I create a User though the web interface, I am not asked to select some categories.
Did I miss somthing ? I read that another table was required but it semmed it was in the case of has_many and not has_and_belongs_to_many statement).
Could you please help ?
I think this is a newby question but...
Thanks a lot,
Regards,
Luc
For HABTM you need a join table called categories_users. Use this migration:
def self.up
create_table :categories_users, :id => false do |t|
t.integer :category_id
t.integer :user_id
end
end
What does your view look like? Rails's scaffolding won't account for many-to-many, so you will need to handle it yourself.
What does your data store look like? If you are using a RDBMS, then for many to many relations you typically need a junction table. Many-to-many is not naturally handled by most (all?) SQL databases.

Associate one model to two different models?

Hey guys. I'm trying to build this Picture Battle site, (where you chose the picture you prefer) and I had two models. Pictures, and Battles.
So Each Picture has_many Battles, but Each Battle belongs to two pictures. How do I associate it.. I was thinking something like "belongs_to_many" but apparently that doesn't exist.
from what i see this could be easily done by using a has_and_belongs_to_many association
You should set up a has_many :through relationship if you need to work with the relationship model as an independent entity. If you don’t need to do anything with the relationship model, which is probably the case, it may be simpler to set up a has_and_belongs_to_many relationship
here's how you do the HABTM:
class Picture < ActiveRecord::Base
has_and_belongs_to_many :battles
end
and
class Battle < ActiveRecord::Base
has_and_belongs_to_many :pictures
end
then you can call picture.battles and battle.pictures
you will also need to create a new migration that looks like this
class CreateBattlesPicturesJoinTable < ActiveRecord::Migration
def self.up
create_table :battles_pictures, :id => false do |t|
t.integer :battle_id
t.integer :picture_id
end
end
def self.down
drop_table :battles_pictures
end
end
more info here
It is a many-to-many association. You can achieve it through a join model. Check has_many in the API docs

Resources