Creating an association from an object - ruby-on-rails

class Group < ActiveRecord::Base
has_many :memberships
has_many :users, through: :memberships
end
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
The following successfully creates an new association in the memberships table:
def create
#group = Group.find(params[:group_id])
current_user.groups << #group
flash[:success] = "You have successfuly joined this group."
respond_to do |format|
format.html {redirect_to #group}
format.js
end
end
However I would like to test the association has been created first and display an appropriate flash message such as:
def create
#group = Group.find(params[:group_id])
membership = current_user.memberships.create(#group)
if membership.save
flash[:success] = "You have successfuly joined this group."
else
flash[:error] = "Unable to join this group."
end
respond_to do |format|
format.html {redirect_to #group}
format.js
end
end
This code however errors with:
"ArgumentError (When assigning attributes, you must pass a hash as an argument.):"
Is it possible to create an association using an existing object?

membership = current_user.memberships.create({group_id: #group.id})

Related

How to clean code and eliminate the NoMethodError exception

When a user creates an accounts, the code should allow that user to register a user account through Devise and then create an account, plus a company.
The code should redirect to a wizard setup using the wicked gem.
Users have roles (rolify) and are authorized with Cancancan.
The tables are setup using has_many :through association. This seems to work.
The models are as follows:
user
has_many :accounts_users
has_many :accounts, through: :accounts_users, dependent: :destroy
has_one :company, through: :accounts, dependent: :destroy
users_account
belongs_to :account
belongs_to :user
account
resourcify
has_many :accounts_users
has_many :users, through: :accounts_users, dependent: :destroy
has_one :company
company
belongs_to :account
The create account controller is the following:
def new
#account = Account.new
end
def create
if !current_user.present?
build_resource(sign_in_params)
account = Account.find_or_create_by(org_name: params[:user] [:account])
else
#account = current_user.accounts.create!(account_params)
end
# create a default account and company
#account.save!
current_user.add_role 'owner'
current_account = current_user.accounts.first
# create a company associated with the newly created account
if current_account.companies.empty?
company = current_account.companies.create(company_name: params[:org_name])
else
company = current_account.companies.first
end
resource.update(current_company: company.id)
respond_to do |format|
if #account.save
# redirect to the relevant wizard
format.html { redirect_to after_account_path(:add_account), notice: 'Account was successfully created.' }
else
format.html { render action: 'new' }
format.json { render json: #account.errors, status: :unprocessable_entity }
end
end
end
EDITED VERSION
def create
#account = Account.create(account_params.except(:company))
#account.save!
respond_to do |format|
if #account.save
create_company
format.html { redirect_to #account, notice: 'Account was successfully created.' }
format.json { render :show, status: :created, location: #account }
else
format.html { render :new }
format.json { render json: #account.errors, status: :unprocessable_entity }
end
end
end
def create_company
current_user.add_role 'owner'
current_account = current_user.accounts.first
if current_account.company.nil?
current_account.build_company(company_name: params[:org_name])
#company.save!
else
company = current_account.company
end
resource.update(current_company: company.id)
end
included in Application helper:
def current_account
current_user.accounts.first
end
def current_company
current_user.accounts.first.companies.first
end
it redirects (unexpected) to displaying (show) the Company data right after creation, I receive a nil / no method error.
the index and how controller are:
before_action :set_company, only: [:show, :edit, :update, :destroy,
:new]
def index; end
def show
#company = Company.find_by(id: params[:id])
end
def set_company
#company = current_account.company
end
This seems to work. Editing the Company is a challenge but should get there.
Any advices to get to a better code is welcome
Have you thought about just making the front end handle the case where #name isn't set yet?
<=% #company&.name %>
or
<=% #company.name || "Unknown" %>

Rails - destroying membership/ownership in user group

I need to be able to "destroy" group ownership when I "destroy" membership of a group if a user is the owner of the group. I have "User", "Group/Cliq", and "Group/CliqMembership" models. When a user creates the group they are the "owner" of the group. Other users can then join the group. When a user leaves the group the membership association for that user and group is destroyed. However, when an owner leaves the group it only removes the "membership" and not the "ownership". I feel like there should be an easy solution, but I'm kind of stuck.
For clarity: Cliqs = Groups; the question is: how do I delete the ownership association and the membership association at the same time? When an "owner" leaves a group I want it to destroy their "group ownership" and their "group membership". As an aside: how would I make the owned group "destroy dependent" when the "owner" leaves?
Here are my models:
class Cliq < ActiveRecord::Base
belongs_to :owner, class_name: 'User'
has_many :cliq_memberships
has_many :members, through: :cliq_memberships, source: :user
end
class CliqMembership < ActiveRecord::Base
belongs_to :cliq
belongs_to :user
end
class User < ActiveRecord::Base
has_one :owned_cliq, foreign_key: 'owner_id', class_name: 'Cliq', dependent: :destroy
has_many :cliq_memberships
has_many :cliqs, through: :cliq_memberships
.
.
.
end
And my controllers:
class CliqsController < ApplicationController
def show
#cliq = Cliq.find(params[:id])
end
def new
#cliq = Cliq.new(params[:id])
end
def create
#cliq = current_user.build_owned_cliq(cliq_params)
#cliq.members << current_user
if #cliq.save
redirect_to current_user
else
redirect_to new_cliq_path
end
end
def destroy
#cliq = current_user.owned_cliq.find(params[:id])
flash[:alert] = "Are you sure you want to delete your Cliq? Your Cliq and all of its associations will be permanently deleted."
#cliq.destroy
if #cliq.destroy
redirect_to current_user
flash[:notice] = "You deleted the Cliq."
else
redirect_to current_user
#set up error handler
flash[:notice] = "Failed to delete Cliq."
end
end
def cliq_params
params.require(:cliq).permit(:name, :cliq_id)
end
class CliqMembershipsController < ApplicationController
def show
end
def create
#Cliq or Cliq_ID?
#cliq = Cliq.find(params[:cliq])
#cliq_membership = current_user.cliq_memberships.build(cliq: #cliq)
#cliq.members << current_user
if #cliq_membership.save
flash[:notice] = "Joined #{#cliq.name}"
else
#Set up multiple error message handler for rejections/already a member
flash[:notice] = "Not able to join Cliq."
end
redirect_to cliq_url
end
def destroy
#cliq_membership = current_user.cliq_memberships.find(params[:id])
#cliq_membership.destroy
if #cliq_membership.destroy
flash[:notice] = "You left the Cliq."
redirect_to user_path(current_user)
else
end
end
end
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#uploads = Upload.all
#cliq_memberships = CliqMembership.all
#cliqs = Cliq.all
end
end
In your CliqMemberships controller's destroy action, right before destroying the CliqMembership, you can check for the current_user's ownership of the group just like you're checking for his/her membership. I'm assuming you want an implementation wherein if the owner leaves the group, you want the group to automatically be destroyed too, along with all its memberships. (Correct me if I'm wrong on that.) In that case, you can add dependent: :destroy to has_many :cliq_memberships
If the current_user happens to be the owner, you can destroy the cliq altogether which would in turn destroy its cliq_memberships too.
You can do it like this in CliqMemershipsController's destroy action.
def destroy
#cliq_membership = current_user.cliq_memberships.find(params[:id])
#cliq = #cliq_membership.cliq
if #cliq.owner == current_user
#cliq.destroy
flash[:notice] = "The Cliq is destroyed"
redirect_to user_path(current_user)
else
# destroy only the membership
flash[:notice] = "You left the Cliq."
redirect_to user_path(current_user)
end
end

Update many-to-many association in rails (User-Team relationship aka Membership)

I just created a create feature for adding a team together with adding the members to a said team.
The form contains the following:
Name of the team.
Team's department.
Leader (value is the user id, but displayed as full name)
Members (values are user ids, but displayed also as full names) //I used a special select menu called select2.
Here are the models. I'll only show the associations and some methods related to my problem.
user.rb
class User < ActiveRecord::Base
has_many :memberships
has_many :teams, through: :memberships
accepts_nested_attributes_for :memberships, :teams
end
team.rb
class Team < ActiveRecord::Base
has_many :memberships
has_many :teams, through: :memberships
accepts_nested_attributes_for :memberships, :users
def build_membership(user_ids)
unless user_ids.blank?
user_ids.each do |id|
self.users << User.find_by_id(id)
end
end
end
end
membership.rb
class Membership < ActiveRecord::Base
belongs_to :team
belongs_to :user
#Note that leader and members are both users
end
Here is the controller, with the create and update methods.
class TeamsController < ApplicationController
def create
#team = Team.new(team_params)
#team.build_membership(build_members_array(members_params))
if #team.save
flash.now[:success] = 'Team was successfully created.'
redirect_to #team
else
flash.now[:notice] = #team.errors.full_messages
render "new"
end
end
def update
# TO-DO: update leader and members (i.e. add or remove member)
if #team.update(team_params)
flash.now[:success] = "Team was successfully updated."
redirect_to #team
else
flash.now[:notice] = #team.errors.full_messages
render "edit"
end
end
private
def team_params
params.require(:team).permit(:name,:department)
end
def members_params
params.require(:team).permit(:leader, members:[])
end
def build_user_ids_array(members)
#put ids of leader and members in an array
end
end
It seems that only the name and department attributes are only updated while the leader and the members are not. Should I create my own method again for updating the roster of the team or do something else in mind?
#team.build_membership would be if you are passing in the params to create a new user, but you are using existing User's so this wouldn't apply. You will want to instead fetch all of the User's by their id and then add that the the Team. You also need to permit the id in the members_attributes in your member_params method.
Something like:
def create
#team = Team.new(team_params)
#team.memberships << users_from_params
if #team.save
flash.now[:success] = 'Team was successfully created.'
redirect_to #team
else
flash.now[:notice] = #team.errors.full_messages
render "new"
end
end
def members_params
params.require(:team).permit(:leader, members_attributes: [:id])
end
def users_from_params
#This members_params[:members_attributes].values should be an array of `id`s
User.find(members_params[:members_attributes].values)
end

NameError with a Many to Many association

I'm trying to add a Join/Unjoin button to user created Events, similar to a Follow/Unfollow button for Users.
I'm not sure what to define #rsvps as in the event#show
NameError in Events#show
undefined local variable or method `event' for #<#:0x007f9dfaf9d978>
show.html.erb
<%= link_to "Join Event", rsvps_path(:event_id => event), :method => :post %>
events_controller.rb
def show
#event = Event.find(params[:id])
#user = current_user
##rsvp = ???? something here ????
end
rsvps_controller.rb
class RsvpsController < ApplicationController
before_filter :signed_in_user
def create
#rsvp = current_user.rsvps.build(:event_id => params[:event_id])
if #rsvp.save
flash[:notice] = "Joined event."
redirect_to root_url
else
flash[:error] = "Unable to join event."
redirect_to root_url
end
end
def destroy
#rsvp = current_user.rsvps.find(params[:id])
#rsvp.destroy
flash[:notice] = "Unjoin Event."
redirect_to current_user
end
end
Here are the models
rsvp.rb
class Rsvp < ActiveRecord::Base
attr_accessible :event_id, :user_id
belongs_to :user
belongs_to :event
end
user.rb
has_many :rsvps
has_many :events, through: :rsvps, dependent: :destroy
event.rb
belongs_to :user
has_many :rsvps
has_many :users, through: :rsvps, dependent: :destroy
Your undefined local variable or method error seems to be coming from trying to pass :event_id => event to your controller through rsvp_path. Instead you should just be passing the event object like so
<%= link_to "Join Event", rsvps_path(event), :method => :post %>
the line #event = Event.find(params[:id]) in your controller will take care of figuring out what event you passed to it.
I think this code would be more rails-ish.
# user.rb
has_many :users_events
has_many :events, through: :users_events
# event.rb
has_many :users_events
has_many :users, through: :users_events
# users_event.rb
belongs_to :user
belongs_to :event
ActiveRecord do everything else. 8)
For example user.events and event.users methods.
Join and unjoin to user actions may be processed by events controller. Update method can look like this
# events_controller.rb
def update
respond_to do |format|
#event = Event.find(params[:id])
#event.users << current_user if params[:action] == 'join'
#event.users.delete(current_user) if params[:action] == 'unjoin'
if #event.update_attributes(params[:event])
format.html { redirect_to #event, notice: 'Event was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #event.errors, status: :unprocessable_entity }
end
end
end
A little bit messy, but I hope the idea is clear.

Add current_user Devise to Mongoid relations

Hi Guys I have a Relationships in Mongoid and I can not add current_user to this relation for get the user that create the deal. A relation with 3 model.
I have three models user.rb, house.rb and deal.rb
user.rb Relationships (devise model)
# Relationships
has_many :houses, dependent: :destroy
has_many :deals, dependent: :destroy
key :title
house.rb
# Relationships
belongs_to :user
embeds_many :deals
deal.rb
# Relationships
embedded_in :house, :inverse_of => :deals
belongs_to :user
In my routes.rb
resources :houses do
resources :deals
end
In my houses_controller.rb in my create method I get current_user for each house of this side:
def create
##house = House.new(params[:house])
#house = current_user.houses.new(params[:house])
respond_to do |format|
if #house.save
format.html { redirect_to #house, notice: 'House was successfully created.' }
format.json { render json: #house, status: :created, location: #house }
else
format.html { render action: "new" }
format.json { render json: #house.errors, status: :unprocessable_entity }
end
end
end
In my deals_controller.rb I have the created method this:
def create
#house = House.find_by_slug(params[:house_id])
#user = User.find(:user_id)
#deal = #house.deals.create!(params[:deal])
redirect_to #house, :notice => "Comment created!"
end
How I can add to this last method create, the current_user that created the deal?
You can simply add these two lines to the create action:
#deal.user=current_user
#deal.save
And I would also suggest you not to use create! instead you should use .new and .save like in the scaffolded create actions! ;)

Resources