Calling a Rails 5 action from one controller to another - ruby-on-rails

I am creating an application that has users and accounts. My issue is that I created the users model and authentication function first but then realized I need to have users belong to accounts.
If I signup a user at route http://lvh.me:3000/signup it will create a new user, send an activation email and activate a user. Works great except it doesn't create the Account. But now, I need to add an account in the mix. If I sign up at my new route http://lvh.me:3000/accounts/new it will create the account and the user, but I need to send the activation email so I can actually activate the user. I can't seem to get my Account controller to trigger the #user.send_activation_email in the create action inside my UserController -- see code below. I know the way I have it below is not the right way, but I've hit a brick wall and not sure where to go from here.
user.rb
class User < ApplicationRecord
has_many :memberships
has_many :accounts, through: :memberships
accepts_nested_attributes_for :accounts
...
# Sends activation email.
def send_activation_email
UserMailer.account_activation(self).deliver_now
end
...
account.rb
class Account < ActiveRecord::Base
belongs_to :owner, class_name: 'User'
accepts_nested_attributes_for :owner
has_many :memberships
has_many :users, through: :memberships
end
accounts_controller.rb
class AccountsController < ApplicationController
def new
#account = Account.new
#account.build_owner
end
def create
#account = Account.new(account_params)
if #account.save
#user.send_activation_email
flash[:info] = 'Please check your email to activate your account.' # Use this for registered users
# flash[:info] = 'Please have user check their email to activate their account.' # Use this for admin created users
redirect_to root_url
else
flash.now[:alert] = 'Sorry, your account could not be created.'
render :new
end
end
private
def account_params
params.require(:account).permit(:organization, owner_attributes: [:name, :email, :password, :password_confirmation])
end
end
users_controller.rb
class UsersController < ApplicationController
...
def create
#user = User.new(user_params)
if #user.save
#user.send_activation_email
flash[:info] = 'Please check your email to activate your account.' # Use this for registered users
# flash[:info] = 'Please have user check their email to activate their account.' # Use this for admin created users
redirect_to root_url
else
render 'new'
end
end
...
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation, accounts_attributes: [:organization])
end
...

If you need both models created as part of the signup flow, then have a single action in a single controller that triggers your signup flow and creates both records.
You can implement this in a number of ways, such as having the Users#signup action create the user and the account inside a transaction, or you can move that logic out of your controller and into your model layer and provide a User.signup method that creates the account explicitly or in an after_create callback.
Either way, the fix here is to simplify and unify your signup flow, not to split it up across several controllers. You only ever need to do that if you have some kind of multi-step signup that requires the user to perform some action between steps.

Related

Create record for another model when account is created?

I have a multi-tenant application. When an account is created, the account belongs to an owner and also creates a user record for the owner. This owner can invite other users through a memberships join table. All users except for account owners have memberships to the account.
For users with memberships (not owners of accounts) the account/users/:id show page shows up. I would like the same for account owners, but am receiving the following error message:
ActiveRecord::RecordNotFound in Accounts::UsersController#show
Couldn't find User with 'id'=2 [WHERE "memberships"."account_id" = $1]
def show
#user = current_account.users.find(params[:id])
end
I can add a membership to the owner user in the admin panel and this error goes away, however I would like to add the membership to the owner/user when they create their account.
Any ideas?
Adding #account.memberships.build(user_id: current_user, account_id: current_account) before if #account.save in the accounts controller below does not seem to work.
controllers
user.rb
module Accounts
class UsersController < Accounts::BaseController
before_action :authorize_owner!, only: [:edit, :show, :update, :destroy]
def show
#user = current_account.users.find(params[:id])
end
def destroy
user = User.find(params[:id])
current_account.users.delete(user)
flash[:notice] = "#{user.email} has been removed from this account."
redirect_to users_path
end
end
end
accounts_controller.rb
class AccountsController < ApplicationController
def new
#account = Account.new
#account.build_owner
end
def create
#account = Account.new(account_params)
if #account.save
sign_in(#account.owner)
flash[:notice] = "Your account has been created."
redirect_to root_url(subdomain: #account.subdomain)
else
flash.now[:alert] = "Sorry, your account could not be created."
render :new
end
end
private
def account_params
params.require(:account).permit(:name, :subdomain,
{ owner_attributes: [:email, :password, :password_confirmation
]}
)
end
end
Models
user.rb
class User < ApplicationRecord
has_many :memberships
has_many :accounts, through: :memberships
def owned_accounts
Account.where(owner: self)
end
def all_accounts
owned_accounts + accounts
end
end
account.rb
class Account < ApplicationRecord
belongs_to :owner, class_name: "User"
accepts_nested_attributes_for :owner
validates :subdomain, presence: true, uniqueness: true
has_many :memberships
has_many :users, through: :memberships
end
membership.rb
class Membership < ApplicationRecord
belongs_to :account
belongs_to :user
end
Have you tried callback after_create?
If it works, you will need to figure it on client and admin create an account, self assigning (admin) against on create assigning (client).
# models/account.rb
after_create do
self.memberships.create(user_id: self.owner, account_id: self.id)
end
Ended up answering this question by putting this line under if #account.save:
if #account.save
#account.memberships.create(user_id: #account.owner.id, account_id: #account.id)
Probably not ideal, but it works for now. I might end up making a service or something like that for it, though.

Can Access data of associated model in console but not in app

In my app i have two types of users: students and companies.
During the registration process, i manage with the wicked gem, the user is asked to fill in data depending on the accounttype (student or company) he chose.
For example, a student have to fill in his university, a company have to fill in the amount of employers.
When the registration process is finished, everything is fine, but somehow i cant access the data of the user which chose accounttype 2 - company.
The data is stored in two seperated associated models:
For students: accountinfo (ye i know its against convention and should have the name account_info)
For companies: accountinfos_company (ye i know, weird pluralization .. but it does the trick and i am not confused by it)
Everything works fine for the students. I am able to fill in data and the data is properly saved within a nested form. Same goes for the companies but unfortunately i am not able to output the data of accountinfos_company in my app. What i can do is for example:
#user.accountinfo.description
For student-accounts. But if I try:
#user.accountinfos_company.description
The output fails with an error
undefined method `accountinfos_company' for #<User::ActiveRecord_Relation:0x007fc1851e6e20>
SOMEHOW I am able to output the data of the particular user via console like: User.last.accountinfos_company.description. I copied every step I made for the first associated model, the data gets properly saved but I am not able to access it inside the app.
I thought it might be something missing, some definition or sth like this but as far as i can see, everything is fine.
users_controller.rb (User association stuff gets created in another controller)
class UsersController < ApplicationController
before_action :authenticate_user!
def index
redirect_to root_path
end
def create
#user = User.create( user_params )
end
def show
#user = User.find(params[:id])
if #user.not_complete?
redirect_to user_steps_path
else
render 'show'
end
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
# might be the right way?
#user.update(user_params)
if #user.update(user_params)
redirect_to User.find(params[:id]), notice: 'Profil bearbeitet.'
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :accounttype,
:accountinfo, :accountinfos_company, :profile_image, :active, accountinfo_attributes:[:id], accountinfos_company_attributes:[:id])
end
end
user_steps_controller.rb
class UserStepsController < ApplicationController
include Wicked::Wizard
steps :welcome, :info
before_action :authenticate_user!
def show
#user = current_user
render_wizard
end
def create
#user = current_user
if #user.accounttype == 1
#accountinfo = #user.accountinfo.create(user_params)
elsif #user.accounttype == 2
#accountinfos_company = #user.accountinfos_company.create(user_params)
end
end
def update
#user = current_user
#user.update(user_params)
render_wizard #user
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :accountinfo, :accountinfos_company,:profile_image, :active, accountinfo_attributes:[:id, :city, :competence, :description, :university], accountinfos_company_attributes:[:id, :city, :company_type, :description, :company_name, :employer_amount])
end
private
def redirect_to_finish_wizard_path
redirect_to root_path, notice: "Danke für deine Zeit!"
end
end
user.rb
class User < ApplicationRecord
has_one :accountinfo
has_one :accountinfos_company
has_many :offer_posts
has_many :search_posts
accepts_nested_attributes_for :accountinfo, update_only: true
accepts_nested_attributes_for :accountinfos_company, update_only: true
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates_presence_of :first_name, :last_name, :email, :accounttype
end
accountinfo.rb and accountinfos_company.rb
belongs_to :user
I dont know if i have something missed but yeah.
If you could help me i would be really glad.

Assign User to a Company on sign up

Let's say I have a User model:
class User
has_secure_password
belongs_to :company, required: true
end
And a Company model:
class Company
has_many :users, dependent: :destroy
end
I wand to create a form that assigns the User to a Company, either a new one if my app doesn't have a record with that company name, or a pre-existing Company.
This is what I have so far, but I am sure there is dryer method...
class UsersController
def create
user = User.new(user_params)
user.company = Company.find_by_name(params['company']) || Comapny.create(name: params['company'])
if user.save
redirect_to root_path
else
redirect_to singup_path
end
end
end
Thanks!
You could use first_or_create:
user.company = Company.where(name: params['company']).first_or_create
...which basically does what it says on the tin.

rails validating the number of users on the account model

I have an app where a user has many accounts and an account has one user. I'm trying to create a setup where an account manager can add a user from the database by entering their e-mail address or if someone is not already a user they are added to the database and then added to the account. I want to limit the number of users that can be added to each account.
class Account < ActiveRecord::Base
has_many users
end
class User < ActiveRecord::Base
belongs_to account
validates_each :account do |user, attr, value|
user.errors.add attr, "too many users for account" if user.account.users.size >= 6
end
end
I found a great validation resource here: Best practice for limiting the number of associations within a has_many relationship? This works great for limiting the number of users but when I try to create a new user (either entering an unknown email or from the normal sign up path) it throws the error
undefined method `users' for nil:NilClass
I also have an add_user controller to control how users are added to the account
class AddUsersController < ApplicationController
before_action :get_user, only: [:edit, :update]
def new
end
def edit
end
def create
#user = User.find_by(email: params[:user][:email])
if #user
#user.add_user_to_account(params[:account_id])
flash[:info] = "Added User to Account"
redirect_to accounts_url
else
email = params[:user][:email]
generated_password = rand_password=('0'..'z').to_a.shuffle.first(8).join
#user = User.new(:name => "New User", :email => email, :password => generated_password, :password_confirmation => generated_password )
#user.save
#user.create_reset_digest
#user.add_user_to_account(params[:account_id])
#user.send_lab_invited_email
flash[:info] = "Email sent to user"
redirect_to accounts_url
end
end
def update
end
private
def user_params
params.require(:user).permit(:account_id, :user_id)
end
def get_user
#user = User.find_by(email: params[:email])
end
end
I think it has something to do with the fact that the user doesn't have an account so it can't find the account.users but most users won't have accounts until they are assigned one by the account manager. Can anyone shed light on how I can fix this issue? Can I write an if statement in the model like if current user or maybe instead define the validation in the AddUser Controller?
UPDATE:
This is my add_user_to_account method
def add_user_to_account(account_id)
update_attributes(account_id: account_id)
end
Try this:
validates_each :account do |user, attr, value|
user.errors.add attr, "too many users for account" if value.users.size >= 6
end
First of all, I think you don't need validates_each since you're validating only one field.
Secondly, you can add a if option to the validation.
So what you want is:
class User < ActiveRecord::Base
belongs_to account
validates :maximum_users_per_account if: :account
... Your code ...
private
def maximum_users_per_account
errors.add :account, "too many users for account" if user.account.users.count >= 6
end
end

Changing roles in rails 4

I created the app with the help of rails composer. Using devise for authentication and cancan for managing roles. So I have 3 roles by default: Admin, User and VIP. I deleted VIP, because I don't need it. Run rake db:seed to create a default admin. Then I'm coming to localhost and seeing the "First User" as admin. I logout and register(signup) a new user. Then, signing in again as admin. I see, that by deafault, this new user doesn't have any role. And also I see, that I can change it("Change role" - button). I push it and as admin can choose whether new user will be the second admin or just User. I choose, for example, User, push "change role" and have an "ArgumentError in UsersController#update wrong number of arguments (2 for 1)".
Sooo, I have two questions:
1. How to give my admin the ability to change roles without errors.
2. How to make new signing up users to have default role "User".
Thanks!
Ok, I managed to set the default role this way:
after_create :assign_reader_role
private
def assign_reader_role
self.add_role "user"
end
Here is my UserControlle:
class UsersController < ApplicationController
before_filter :authenticate_user!
def index
authorize! :index, #user, :message => 'Not authorized as an administrator.'
#users = User.all
end
def show
#user = User.find(params[:id])
end
def update
authorize! :update, #user, :message => 'Not authorized as an administrator.'
user = User.find(params[:id])
if user.update_attributes(user_params)
redirect_to users_path, :notice => "User updated."
else
redirect_to users_path, :alert => "Unable to update user."
end
end
def destroy
authorize! :destroy, #user, :message => 'Not authorized as an administrator.'
user = User.find(params[:id])
unless user == current_user
user.destroy
redirect_to users_path, :notice => "User deleted."
else
redirect_to users_path, :notice => "Can't delete yourself."
end
end
private
def user_params
params.require(:user).permit(:name, :email)
end
end
Here is models.
User:
class User < ActiveRecord::Base
after_create :assign_reader_role
rolify
devise :database_authenticatable, :registerable,#:confirmable,
:recoverable, :rememberable, :trackable, :validatable
validates_presence_of :name
private
def assign_reader_role
self.add_role "user"
end
end
Role:
class Role < ActiveRecord::Base
has_and_belongs_to_many :users, :join_table => :users_roles
belongs_to :resource, :polymorphic => true
scopify
end
UserController I've already put! And where can I take params from the form?
I think you missed role_ids in permit
def user_params
params.require(:user).permit(:name, :email, :role_ids)
end

Resources