Rails after_create callback to update a different model - ruby-on-rails

I have users, groups, and memberships. I have a has_many through relationship set up between users and groups using the membership join table. What I am trying to do is set up an after_create callback that adds a new record into the memberships table whenever a user creates a new group, that way the creator is automatically a member of the group.
Right now, a user can create a group, but the group will display having 0 members, and the user will have to join the group. How can I automate that part with the callback if I'm trying to update the membership Model from the Group controller?
user.rb
class User < ApplicationRecord
has_many :created_groups, class_name: "Group"
has_many :memberships
has_many :groups, through: :memberships
end
group.rb
class Group < ApplicationRecord
belongs_to :creator, class_name: "User"
has_many :memberships
has_many :users, through: :memberships
end
membership.rb
class Membership < ApplicationRecord
belongs_to :user
belongs_to :group
end
groups_controller.rb
class GroupsController < ApplicationController
after_create :set_membership
def create
#group = current_user.groups.build(group_params)
respond_to do |format|
if #group.save
format.html { redirect_to #group, notice: 'You have a new Group!' }
else
format.html { render :new }
end
end
end
private
def set_membership
end
end
The set_membership part is where I'm completely lost. I just need to grab the created group's id and use it to create a new membership (with current user id).

I'll move set_membership to Group model (active_create is a model callback, so it will not work in a controller), and create the Membership there, like this:
class Group < ApplicationRecord
after_create: set_membership
belongs_to :creator, class_name: "User"
has_many :memberships
has_many :users, through: :memberships
private
def set_membership
Membership.create!(user_id: user_id, group_id: id)
end
end

Related

dependent: :destroy doesn't work on has_one relation

If I delete child record so parent record does not get deleted automatically.
class User < ActiveRecord::Base
has_one :agency, dependent: :destroy
accepts_nested_attributes_for :agency
end
class Agency < ActiveRecord::Base
belongs_to :user
accepts_nested_attributes_for :user
end
if #agency.present?
#agency.user.destroy
flash[:notice] = 'Agency Deleted'
end
Destroy child record so parent record automatically destroy.
I think, your models could be re-written like this to achieve expected output.
class User < ActiveRecord::Base
has_one :agency # Change
accepts_nested_attributes_for :agency
end
class Agency < ActiveRecord::Base
belongs_to :user, dependent: :destroy # Change
accepts_nested_attributes_for :user
end
if #agency.present?
#agency.destroy # Change
flash[:notice] = 'Agency Deleted'
end
Let's think logically now.
What have you changed is, you made User dependent on Agency and now it's rails doable to form a parent-child relationship to get accepted output. So when you destroy an #agency, it will also delete the dependent user record.
You should use the following code to delete a user and its associated agency without making any change to your model.
class User < ActiveRecord::Base
has_one :agency, dependent: :destroy
accepts_nested_attributes_for :agency
end
class Agency < ActiveRecord::Base
belongs_to :user
accepts_nested_attributes_for :user
end
if #agency.present?
user = #agency.user #Change
user.destroy # This will destroy both user and associated agency.
flash[:notice] = 'Agency and User Deleted'
end
A complete official guide on dependent: :destroy can be find here.

Define owner after create

Walls belong to users through a WallAssignments association.
class Wall < ApplicationRecord
belongs_to :user
has_many :wall_assignments
has_many :users, :through => :wall_assignments
end
class User < ApplicationRecord
has_many :wall_assignments
has_many :walls, :through => :wall_assignments
end
class WallAssignment < ApplicationRecord
belongs_to :user
belongs_to :wall
end
In the create action, I'm associating the current user with the new wall record.
def create
#wall = Wall.new
#wall.wall_assignments.build(user_id: current_user.id)
if #wall.save
redirect_to #wall
else
redirect_to current_user
end
end
However, aside from allowing many users to belong to the wall, I'd like to have one user (the user who created it) own the wall.
I'm attempting something like this:
class Wall < ApplicationRecord
after_create { owner }
belongs_to :user
has_many :wall_assignments
has_many :users, :through => :wall_assignments
private
def owner
self.owner = Wall.users.first
end
end
Eventually, I'd like to be able to call #wall.owner.name and #wall.owner.id in my views.
I guess you want to have has_many(as users) and has_one(as owner) with same table User.
In this scenario, your Wall model will be:
class Wall < ApplicationRecord
belongs_to :owner, class_name: 'User', foreign_key: :owner_id
has_many :wall_assignments
has_many :users, :through => :wall_assignments
end
You need to add owner_id column in walls table.
So when you create Wall record, it will
class Wall < ApplicationRecord
after_create { add_owner }
private
def add_owner
self.update_column(:owner_id, self.users.first.id) if self.users.present?
end
end
You can also modify controller's create code(I assumed, create method will get called only once.)
def create
#wall = Wall.new(wall_params)
#wall.owner_id = current_user.id
#wall.wall_assignments.build(user_id: current_user.id)
if #wall.save
redirect_to #wall
else
redirect_to current_user
end
end
with this, you don't need to add after_create callback in Wall model.
And then you can call #wall.owner.name and #wall.owner_id

How to save throught model with extra field?

I have three models Company, User and Division
User have many Division for different Companies
I need to determine in what company owns Divisions
So I build has_many :through association between Users and Divisions
Model UsersDivision have this fields id|user_id|division_id|company_id but when I update User model rails delete old records and create new without company_id field How i can update model UsersDivision and merge company_id ?
Callback?
class UsersDivision < ActiveRecord::Base
after_update :set_company
belongs_to :user
belongs_to :division
belongs_to :company
validates :user_id, :division_id, presence: true
private
def set_company(company)
self.company_id = company
end
end
or in the controller?
class UsersController < ApplicationController
def update
#company = Company.find(params[:company_id])
#user = User.find(params[:id])
if #user.update(user_params)
redirect_to :back
end
end
end
How to merge company_id when create UsersDivision record?
So I build has_many :through association between Users and Divisions
I would expect there to be a table for Divisions, and then a table for CompanyDivisions, and then we can associate users to that.
Here's how I would have it set up:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :user_divisions
has_many :divisions, through: :user_divisions
has_many :company_divisions, through: :user_divisions
has_many :companies, through: :company_divisions
end
#app/models/user_division.rb
class UserDivision < ActiveRecord::Base
belongs_to :user
belongs_to :company_division
end
#app/models/company.rb
class Company < ActiveRecord::Base
has_many :company_divisions
has_many :divisions, through: :company_divisions
end
#app/models/company_division.rb
class CompanyDivision < ActiveRecord::Base
belongs_to :company
belongs_to :division
end
#app/models/division.rb
class Division < ActiveRecord::Base
has_many :company_divisions
has_many :companies, through: :company_divisions
end
This is very bloated, but should give you the ability to call:
#user.divisions
#user.divisions.each do |division|
division.companies.first
How to merge company_id when create UsersDivision record
This will depend on several factors:
params hash
How your associations are set up
I don't have your params hash, but I do have your current code:
class UsersController < ApplicationController
def update
#company = Company.find params[:company_id]
#user = User.find params[:id]
redirect_to :back if #user.update user_params
end
private
def user_params
params.require(___).permit(___).merge(company_id: #company.id)
end
end

Rails insert into db with has_many through

How can i add data in my database with the following model?
class User < ActiveRecord:Base
has_many :user_groups
has_many :groups, through: :user_groups
class Group < ActiveRecord:Base
has_many :user_groups
has_many :users, through: :user_groups
class UserGroup < ActiveRecord:Base
belongs_to :user
belongs_to :group
Now i'm using this code to save the new record
#group_controller
def create
#group = current_user.groups.build(params...)
if #group.save
#my redirect etc...
end
Well, this will create an row in my group table with the corrects parameters etc but my join table is still empty... why? Can anybody explain these? ;)
because you are building the group and saving it, but not the relationship.
if #group.save
current_user.groups << #group
will fix it.

has_many :through default values

I have a need to design a system to track users memberships to groups with varying roles (currently three).
class Group < ActiveRecord::Base
has_many :memberships
has_many :users, :through => :memberships
end
class Role < ActiveRecord::Base
has_many :memberships
has_many :users, :through => :memberships
end
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :role
belongs_to :group
end
class User < ActiveRecord::Base
has_many :memberships
has_many :groups, :through => :memberships
end
Ideally what I want is to simply set
#group.users << #user
and have the membership have the correct role. I can use :conditions to select data that has been manually inserted as such :
:conditions => ["memberships.role_id= ? ", Grouprole.find_by_name('user')]
But when creating the membership to the group the role_id is not being set.
Is there a way to do this as at present I have a somewhat repetitive piece of code for each user role in my Group model.
UPDATED
It should be noted what id ideally like to achieved is something similar to
#group.admins << #user
#group.moderators << #user
This would create the membership to the group and set the membership role (role_id ) appropriately.
You can always add triggers in your Membership model to handle assignments like this as they are created. For instance:
class Membership < ActiveRecord::Base
before_save :assign_default_role
protected
def assign_default_role
self.role = Role.find_by_name('user')
end
end
This is just an adaptation of your example.

Resources