How to load data in a Ruby on Rails Join Table? - ruby-on-rails

I have the following join table that works:
class CreateRolesUsers < ActiveRecord::Migration
def self.up
create_table :roles_users,:id => false do |t|
t.integer :role_id, :null => false
t.integer :user_id, :null => false
end
end
def self.down
drop_table :roles_users
end
end
But I don't know how to load by default some data (syntax), I try that:
roleUser = RoleUser.create(:role_id => 2,:user_id => 1)
roleUser.save!
It does not work, is it RoleUser... or something else to use? RolesUser...etc.

That's provided that you have a model named RolesUser.
If you have a habtm association, the model is probably not there.
One way of loading roles could be;
user = User.create :name => 'John'
role = Role.create :name => 'admin'
user.roles << role

From what I understand, your user can have many roles, right? If so..
class User < ActiveRecord::Base
has_and_belongs_to_many :roles
end
class Role < ActiveRecord::Base
has_and_belongs_to_many :users
end
Then you can do
user = User.create :name => 'John'
role = Role.create :name => 'admin'
roles_users = RolesUser.create :user => user, :role => role
The has_and_belongs_to_many assoiation creates a join table with both FK. If you need extra data in the join table, you will need to use has_may :through instead of has_and_belongs_to_many.
I strongly recommend reading the guide on ActiveRecord associations. Good luck!

You're almost there. The table name is a plural form of the model name. The table is named RolesUsers, so the model is named RolesUser.
Also, I think you would prefer to use the new method if you're going to call save! after the fact. Calling create automatically saves the record.
rolesUser = RolesUser.new(role_id => 2,:user_id => 1)
rolesUser.save!
Recommended reading: http://api.rubyonrails.org/classes/ActiveRecord/Base.html

First when you have association has_and_belongs_to_many you actualy don't have model, you only have database table with plural name combined from models that are participating in association, for example
class User < ActiveRecord::Base
has_and_belongs_to_many :roles
end
class Role < ActiveRecord::Base
has_and_belongs_to_many :users
end
You don't get model named UserRoles, or UsersRoles, or UsersRole or any kind of model, this only makes some methods that you can use on User instance or Role instance to find for 1 user all of his roles, or to find all users with some role ant etc.
This works, that rails will look for database table with name roles_users (it looks for table that is combined with both model names in plural, ordering by alphabetical order, thats why its roles_users and not users_roles).
For particular user you can add roles or predefine existing ones, example:
# find one user
user = User.first
# get collection of roles
roles_c = Role.where("some conditional statement to find roles")
# set user roles to found collection
user.roles = roles_c
# save changes
user.save
This way you will get records in roles_users table with user_id of user and for every role in roles_c collection there will be record, for example:
# if user.id is 1
# and in roles_c you have 3 roles with id_s 2,5 and 34
# in roles_users table there will be created 3 records with
user_id => 1, role_id => 2
user_id => 1, role_id => 5
user_id => 1, role_id => 34
Other way is to add some roles,
user = User.first
roles_c = Role.where('conditional statement')
user.roles << roles_c
user.save

Related

Get the data from association

I have two tables user and group.
user group
----- -------
id id
name group_name
created_by
In my user model I have used , has_and_belongs_to_many :groups, dependent: :destroy
In my group model I have used, has_and_belongs_to_many :users, dependent: :destroy
I have create a migration
class UserGameGroup < ActiveRecord::Migration
def change
create_table :user_game_group, id: false do |t|
t.belongs_to :user, index: true
t.belongs_to :group, index: true
end
end
end
So in my group controller`s show method, I want to fetch users for specific group.
Suppose if I am currently on group 4, I want to fetch all the users based on that group.
I can do this Group.where(group_id: 4) but it will only give me the id of the user. Is there a way to get the name of the user too ?
Suppose if I am currently on group 4, I want to fetch all the users based on that group
#group = Group.find 4
#group.users.each do |user| #-> collection of User objects for #group
user.name
end
Your join table name is wrong.
For has_and_belongs_to_many, it should be [alphabetical_first_plural]_[alphabetical_second_plural], in your case groups_users:
class UserGameGroup < ActiveRecord::Migration
def change
create_table :groups_users, id: false do |t|
t.belongs_to :user, index: true
t.belongs_to :group, index: true
end
end
end
If you wanted to use the table name you have, you'd have to explicitly define the join_tableoption in your model:
#app/models/user.rb
class User < ActiveRecord::Base
has_and_belongs_to_many :groups, join_table: :user_game_groups
end
#app/models/group.rb
class Group < ActiveRecord::Base
has_and_belongs_to_many :users, join_table: :user_game_groups
end
To populate the join table, you can use the << & .delete methods:
#user = User.find x
#group = Group.find y
#user.groups << #group
#user.groups.delete #group
In your current example you're querying for a single group which will have the method users on it. So likewise you could use this call to retrieve a collection of user records.
group = Group.where(group_id: 4)
group.users # Returns a collection of users.
If you want to make a single query you can use ActiveRecord::QueryMethods include method like so.
Group.includes(:user).where(group_id: 4)
You should rename your joining group to groups_users. Rails expect the joining group to be in this format (smaller alphabet of the joining tables first and table named separated by _). plus both should be plural. Also both your table names group and user should be plural such as groups and users otherwise you have to specify the table name manually on the model.
Moreover, in order to fetch the name and other attributes for user, you can do something like
group = Group.find(4)
group_users = group.users
group_users will give you the list of all the users that belong to group with id 4.

Rails Nested Resources Creation

In RoR, whenever you create a nested resource, is there to set attributes during creation of a resource with a parent association, within the model?
I have this Role model that may belong_to and have_many other roles.
employee = Role.find_by_slug :employee
employee.role
=> nil
employee.roles
=> [...more roles...]
waitress = employee.roles.create(slug: :waitress)
=> #<Role id...
waitress.role
=> #<Role slug: 'employee'...
waitress.roles
=> []
The role model has a boolean attribute of subtype. Whenever I create a role from an existing role, I'd like for subtype to be set to true.
employee.subtype
=> false
And waitress would look like this:
waitress.subtype
=> true
Whenever I create a role from an existing role, I'd like for subtype to be set to true.
#app/models/Role.rb
class Role < ActiveRecord::Base
belongs_to :role
has_many :roles
validate :role_exists, if: "role_id.present?"
before_create :set_subtype, if: "role_id.present?"
private
def set_subtype
self.subtype = true
end
def role_exists
errors.add(:role_id, "Invalid") unless Role.exists? role_id
end
end
The above will require another db request; it's only for create & it will happen when the model is invoked (IE you can call it whatever you like when you need it).
--
An alternative to this would be to use acts_as_tree or a similar hierarchy gem.
AAT adds a parent_id column in your db, to which it will then append a series of instance methods you can call (parent, child, etc).
This would permit you to get rid of the has_many :roles, and replace it with a children instance method:
#app/models/role.rb
class Role < ActiveRecord::Base
acts_as_tree order: "slug"
#no need to have "subtype" column or has_many :roles etc
end
root = Role.create slug: "employee"
child1 = root.children.create slug: "waitress"
subchild1 = child1.children.create slug: "VIP_only"
root.parent # => nil
child1.parent # => root
root.children # => [child1]
root.children.first.children.first # => subchild1
According to your description, a given Role is considered a subtype if it has no parent role. In this case, simply add the following method to Role:
def subtype?
!self.role.nil?
end
The following changes did the trick for me:
from:
has_many :roles
to:
has_many :roles do
def create(*args, &block)
args[0][:subtype] = true
super(*args, &block)
end
end

Belongs_to different field name

I've inherited quite a weird table layout:
callbacks
id, note, user
admin
id, name, password
In callbacks, the user is set to the name of the admin rather than the actual ID. Now I need to be able to call callbacks.user and have rails lookup the admin with that name and then bind it to that record.
I have a model for admin that is called users
How would I go about that?
You can override the default methods.
def user
User.find_by_name(user_name)
end
def user=(obj)
self.user_name = obj.name
end
def user_name
self[:user]
end
def user_name=(name)
self[:user] = name
end
Other option , to make it work with belongs_to, there is primary_key option but need to have a different name than the attribute user
# Callback.rb
belongs_to :user_model , :class => "User", :foreign_key => :user, :primary_key => :name
# User.rb
has_one :callback , :foreign_key => :user, :primary_key => :name

How to insert two associated instances in to corresponding tables by using a Migration?

I have two ActiveRecode model, Car and User, which has many-to-one association:
class Car < ActiveRecord::Base
has_many :users
...
end
class User < ActiveRecord::Base
belongs_to :car
...
end
And, I have two tables in database, cars and users. users table has attribute car_id
I would like to have a migration which will insert a car instance to the cars table, meanwhile, there will be a user instance created which has the association with the car instance and will then be inserted to the users table. How to do this in a migration?
That's by run this migration, both the car instance and its associated user instance will be stored in the corresponding tables in database.
I am using Rails 3.
example of migrations
class FillCarsAndUsers < ActiveRecord::Migration
def self.up
#if you have a Corresponding class for table
Corresponding.find(:all).each do |cor|
#save data
car = Car.create(...) #you may save old car id, if need "Car.create(:id => cor.car_id, ...)"
User.create(:car_id => car.id, ...)
...
User.create(:car_id => car.id, ...)
end
end
def self.down
end
end
Try like this
data = {'car1' => ['user1', 'user2'], 'car2' => ['user3'], 'car3' => ['user4']}
data.each do |car, users|
car_obj = Car.create(:name => car)
users.each do |user|
User.create(:name => user, :car_id => car_obj.id)
end
end

Rails - Join Table with Attributes (HABTM + Through) But how do I create / delete records?

I have a User model and Interest Model being joined by a join table called Choice (details below). I'm using the HABTM relationship with through since I have an attribute within the join table as well.
User.rb
has_many :choices
has_many :interests, :through => :choices
Interest.rb
has_many :choices
has_many :users, :through => :choices
Choice.rb
belongs_to :user
belongs_to :interest
So the question is how do I add records to this newly created choice table. For example =>
#user = User.find(1)
#interest = Interest.find(1)
????? Choice << user.id + interest.id + 4(score attribute) ??????
The last part is the part I'm having a problem with..I have these 3 parameters and didn't how to add them in and what the syntax was?
You have a couple options for adding a choice, but what probably makes the most sense would be to add choices by scoping to the user instance:
Assuming:
#user = User.find(1)
#interest = Interest.find(1)
You could add a choice like so:
#user.choices.create(:interest => #interest, :score => 4)
You could also do something like this in your controller:
def create
#choice = #user.choices.build(params[:choice])
if #choice.save
# saved
else
# not saved
end
end
This assumes your form has fields for choice[:interest_id] and choice[:score]

Resources