Rails belongs_to relationship with multiple possibilities - ruby-on-rails

I'm trying to make a relationship where a model, Information, belongs_to either a User or a Client.
I thought about putting in my Information.rb
belongs_to :user
belongs_to :client
and in User.rb and Client.rb
has_one :information
But that makes it so that an information could belong_to both a User and a Client.
Is there a way to make it so that it can only belong to either or without just leaving one of the fields blank?
P.S. If it is needed I'm using Rails 4.2, Ruby 2.2.1, and Devise for my account authentication.
Thanks!

This sounds like an unusual association but it's a good fit for Polymorphic Association. In this case, you would declare a name for this association
class Information < ActiveRecord::Base
belongs_to :informational, polymorphic: true #or something like it
class User < ActiveRecord::Base
has_many informations, as :informational
class Client < ActiveRecord::Base
has_many informations, as :informational
And you would also need to add two columns to Information
informational_id, :integer and informational_type, :string
and Client and User need a integer called informational_id that is indexed.

Related

Rails how to access users status on project level

I have two models User and Project which are in has_and_belongs_to_many association
The user model has a column status
i can access the status of a user who is in project like
project.user.status
but a user can be in different projects i want his status to be on project level instead of on his id
If I understand your question correctly, the problem is that you need to associate the status of the user to one of potentially many projects that the user is associated with, but you are associating a single status to a single user instead of the project.
In that event, you need to abstract this association to an additional model, for instance "UserProjectStatus" which would be associated with both the User and the Project. You can do this using the has_many, through association. This would end up with something along the lines of:
class Project < ApplicationRecord
has_many :user_project_statuses
has_many :users, through :user_project_statuses
end
class UserProjectStatus < ApplicationRecord
belongs_to :user
belongs_to :project
end
class User < ApplicationRecord
has_many :user_project_statuses
has_many :projects, through :user_project_statuses
end
There is a good overview of this any many other Rails ActiveModel associations at https://guides.rubyonrails.org/association_basics.html#the-has-one-through-association.
Hope this helps!

Using a junction table with its own relationship

I'm creating an app that has a User and a Plugin model. A user can have multiple plugins and a plugin can belong to multiple users, which I've implemented using a junction table.
class Plugin < ActiveRecord::Base
has_many :user_plugins
has_many :users, through: :user_plugins
end
class User < ActiveRecord::Base
has_many :user_plugins
has_many :plugins, through: :user_plugins
end
class UserPlugins < ActiveRecord::Base
belongs_to :user
belongs_to :plugin
end
However, I then want to store arbitrary data for each user plugin (for example, things like api keys, options etc that can differ for each plugin.).
My initial approach was to have a user_plugins_options that joined on user_plugins, but I can't seem to get this to work correctly.
class UserPluginOptions < ActiveRecord::Base
belongs_to :user_plugins
end
My question, how should I go about approaching this to best work with ActiveRecord?
I think you misnamed your class, as the table is user_plugins but the model is UserPlugin. It’s plausible you are running into issues because of this.
Agree with Alex. Why don’t you create a json field on UserPlugin called options and keep a hash of plugin specific values here.
If you must have another table, you should add a has_one :user_plugin_option to your UserPlugin

Rails: Multiple relationships between two models

I'm creating a Database Migration in Rails 4.0.4, and I want to capture the following relationship:
A customer has many credit cards. A customer has only one default credit card.
and here's what I think it should look like.
class Customer < ActiveRecord::Base
has_many :cards
has_one :card # i.e. has one default card
end
class Card < ActiveRecord::Base
belongs_to :customer
end
Is this correct? If so, how does Rails know which relationship the belongs_to in the Card class refers to? If it's incorrect (and I'm guessing it is), please help me fix it.
I'd put the scope on the card's side, seems easier for me
class Customer < ActiveRecord::Base
has_many :card
end
class Card < ActiveRecord::Base
belongs_to :customer
scope :default, -> { where is_default: true }
end
default_card = customer.cards.default
Currently your code is enough to confuse Rails by having has_one :card and has_many :cards.You should be using class_name option provided specially for these type of associations.
Something like this should work for you
class Customer < ActiveRecord::Base
has_many :cards
has_one :default_card, :class_name => "Card"
end
foreign_key
To add to Pavan's answer, you'll need to use some sort of condition to determine which is the default card.
Because Rails' relational database structure relies on foreign_keys to pull the related data, you'll need to either assign the correct foreign_key for your default_card, or use a condition to find it:
#app/models/customer.rb
Class Customer < ActiveRecord::Base
has_one :default_card, -> { where default: true" },class: "Card", foreign_key: "customer_id"
end
This would rely on having the boolean column default in your cards table

Ruby on Rails belongs_to vs. has_one associations - clarification requested

In the following instance, what would the difference be between using belongs_to :mother and has_one :mother for the Chlid class? I've been reading the Rails documentation on this and I can't see how either one would make a difference apart from the semantics involved with reading it.
From what I can tell, the various associations add extra methods to each class, but I haven't been able to find the documentation to list per association what the methods are and what they do.
class BiologicalMother < ActiveRecord::Base
has_many :children
end
class Child < ActiveRecord::Base
belongs_to :biological_mother
end
In your case the has_many belongs_to is the right approach not just semantically but as how rails works. The foreign key is always stored in the belongs_to part of the association.
A valid has_one scenario could be like having a Purchase model which has_one BillingAddress.
example:
class Purchase
has_one :billing_address
end
class BillingAddress
belongs_to :purchase #this holds the foreign key - purchase_id
end
Regarding your case, you cant use has_many in one side and has_one at the other side of the association because the belongs_to part holds the foreign key always.
Let me know if this works for you.
At this point, it's almost purely semantics. With mongoid, I know that the foreign key is stored on the model with the belongs_to, so there might be something like that with ActiveRecord too.

Rails STI Style Inheritance for multiple roles per user

I've been reading up on a bit of STI Inheritence examples for Rails,
While it looks like it would suit my needs (User role/types inheriting from a base class of user). It seems like it doesn't handle a user having multiple roles too well. Particularly because it relies on a type field in the database.
Is there a quick and easy work around to this?
I'm not sure if STI is the right solution in a user role/user scenario - I don't think of User roles/types as a specific form of user. I would have the following schema:
class Membership < ActiveRecord::Base
belongs_to :user # foreign key - user_id
belongs_to :role # foreign key - role_id
end
class User < ActiveRecord::Base
has_many :memberships
has_many :roles, :through => :membership
end
class Role < ActiveRecord::Base
has_many :memberships
has_many :users, :through => :membership
end
Another way of doing this would be to use has_and_belongs_to_many. You might also want to check out the restful_authentication plugin.
A good workaround for your problem could be the easy_roles gem. You can find it on github.
As the others already said STI is not the way you can implement your stuff.
Just like Andy said, has_and_belongs_to_many is another way to do this.
# user.rb
class User < ActiveRecord::Base
has_and_belongs_to_many :roles
end
# role.rb
class Role < ActiveRecord::Base
has_and_belongs_to_many :users
end
Note: You still need the association table in your database but it's just hidden from your models.

Resources