Rails Ownership of records in many to many relations - ruby-on-rails

I’m creating a Rails application and I’m having trouble regarding ownership of a record.
I have a many to many relationship and I would like to find the owner/creator of a record.
Models :
class User < ApplicationRecord
has_many :user_accounts
has_many :accounts, through :user_accounts
end
class UserAccount < ApplicationRecord
belongs_to :user
belongs_to :account
end
class Account < ApplicationRecord
has_many :user_accounts
has_many :users, through :user_accounts
end
How could I find the User that actually created the Account ?
I’ve thought about adding a owner_id field in Account with a belongs_to relationship (e.g. : belongs_to :owner, class_name: 'User' ), but I wanted to know if there was any other way or better way to achieve that ?

The solution you proposed (adding owner_id to Account) is a perfectly valid one. Here's a few more.
Add primary or owner boolean into UserAccount. Since you already have a reference to account, it might be better to use that instead of adding another relation.
Another (!dangerous!, but) with no additional columns would be to look for the earliest UserAccount according to created_at or similar. I suggest against this though, because any data migration you might do down the line might break this.

Related

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 ActiveRecord association "has_many, each of which has_one"

I have a question regarding ActiveRecord associations, where I'm trying to have a User model, where each user can have many Products (which then belong to that specific user). However, before the product is on display, it needs an active permission, so I want to add a third model, Permission, to said construct.
I formulated following sentence to make the thinking process easier:
One User has_many Products, each of which has_one Permission.
The ActiveRecord associations look like this right now:
class User < ActiveRecord::Base
has_many :products
has_many :permissions
end
class Product < ActiveRecord::Base
belongs_to :user
has_one :permission
end
class Permission < ActiveRecord::Base
belongs_to :product
belongs_to :user
end
My questions:
is this the correct approach (does it actually work?)
is it necessary to declare that User has_many permissions and Permission belongs_to user if I never need to list all permissions of a user in my app?
I want to ask you guys for confirmation if my thoughts are correct or if it's wrong or if there is a better way to master my problem and I hope the question is also useful to others, thanks!
I'll answer both questions at the same time. The code will work (given the correct migrations), but not for what you want. Remove the has_many :permissions from the User class and belongs_to :user from the Permission class.
It's ok.
It should be has_many :permissions, through: :products, if you want it is able to get permissions from a user, but in permissions table does not contain user_id column.
The db query is generated like:
SELECT "permissions".*
FROM "permissions" INNER JOIN "products" ON "permissions"."product_id" = "products"."id"
WHERE "products"."user_id" = [user_id]

Enforcing uniqueness of a model in has_many though

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 :)

Proper Rails Association to use

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

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