I have 2 controllers User and Rota. I want the user to be able to create their own Rota but only be able to edit, show and destroy their own. I need to be able to code so that my rotum object belongs to the user object.
ROTA CONTROLLER:
class RotaController < ApplicationController
respond_to :html, :xml, :json
before_action :set_rotum, only: [:show, :edit, :update, :destroy]
def edit
#rotum = #user.rota.find params[:id]
end
def index
#rota = Rotum.all
respond_with(#rota)
end
def show
respond_with(#rotum)
end
def new
#rotum = Rotum.new
respond_with(#rotum)
end
def edit
end
def create
#rotum = Rotum.new(rotum_params)
#rotum.save
respond_with(#rotum)
end
def update
#rotum.update(rotum_params)
respond_with(#rotum)
end
def destroy
#rotum.destroy
respond_with(#rotum)
end
private
def set_rotum
#rotum = current_user.rotums.find(params[:id])
if #rotum.nil?
render :html => "Not authorized", :status => 401
end
end
def rotum_params
params.require(:rotum).permit(:name, :email, :mobile, :category)
end
end
USER CONTROLLER
class UsersController < ApplicationController
before_filter :authenticate_user!
after_action :verify_authorized
def index
#users = User.all
authorize User
end
def show
#user = User.find(params[:id])
authorize #user
end
def update
#user = User.find(params[:id])
authorize #user
if #user.update_attributes(secure_params)
redirect_to users_path, :notice => "User updated."
else
redirect_to users_path, :alert => "Unable to update user."
end
end
def destroy
user = User.find(params[:id])
authorize user
user.destroy
redirect_to users_path, :notice => "User deleted."
end
def edit
#rotum = #user.rota.find params[:id]
end
private
def secure_params
params.require(:user).permit(:role)
end
end
So far my rota allows anyone to create, show, edit and destroy the rota on the rotas page. I only want the user to be able to edit only THEIR OWN rota that they created. For that I have been told tell the rota object to belong to the user object. How can I do this in my controllers or models.
USER MODEL
class User < ActiveRecord::Base
has_many :rota, dependent: :destroy
enum role: [:user, :vip, :admin]
after_initialize :set_default_role, :if => :new_record?
def set_default_role
self.role ||= :user
end
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
ROTUM MODEL
class Rotum < ActiveRecord::Base
belongs_to :user
end
I get the error:
NoMethodError at /rota/15
undefined method `rotums' for #
You are not showing your models, so I'm assuming that you have a has_many relationship
class User < ActiveRecord::Base
has_many :rota, dependent: :destroy
end
class Rotum < ActiveRecord::Base
belongs_to :user
end
then in your controller you can use the following:
class UsersController < ApplicationController
....
def edit
#rotum = #user.rota.find params[:id]
end
Note that this will raise an ActiveRecord::RecordNotFound exception if a user is triying to edit a rotum that does not belong to him.
You can avoid that problem with the following:
class UsersController < ApplicationController
....
def edit
#rotum = #user.rota.find_by id: params[:id] # returns nil in case the record does not exist or does not belong to #user
redirect_to "somewhere", alert: 'You cannot edit this element' if #rotum.blank?
end
Related
I have a User model. A user can be an employer or a student. So there is an employer model and a student model. They both belong to user. Only employers can view student profiles. So if there is something wrong with the profile, the employer should be able to report the profile. I was thinking of having a "report" button on the profile which only the employers can see. Then when they click on it, the admin (me) gets an email with the url or the id of the student.
Right now, the student profile url looks like www.mywebsite.com/students/john-big. How can the report button be setup so the whole URL or the user-id (John-big) gets emailed to me.
The mailer is set up already because I set it up in a way where I get an email every time a user signs up. I can use the same logic to email myself, but grabbing the ID or url is the problem. What is the best way to do it?
Userinfo controller (userinfo =student):
class UserinfosController < ApplicationController
before_action :find_userinfo, only: [:show, :edit, :update, :destroy, :log_impression]
before_action :authenticate_user!
def index
end
def show
end
def new
#userinformation = current_user.build_userinfo
end
def create
#userinformation = current_user.build_userinfo(userinfo_params)
if #userinformation.save
redirect_to userinfo_path(#userinformation)
else
render 'new'
end
end
def edit
end
def update
if #userinformation.update(userinfo_params)
redirect_to userinfo_path(#userinformation)
else
render 'edit'
end
end
def destroy
#userinformation.destroy
redirect_to root_path
end
private
def userinfo_params
params.require(:userinfo).permit(:name, :email, :college, :gpa, :major)
end
def find_userinfo
#userinformation = Userinfo.friendly.find(params[:id])
end
end
Employer controller:
class EmployersController < ApplicationController
before_action :find_employer, only: [:show, :edit, :update, :destroy]
def index
end
def show
end
def new
#employer = current_user.build_employer
end
def create
#employer = current_user.build_employer(employer_params)
if #employer.save
redirect_to userinfos_path
else
render 'new'
end
end
def edit
end
def update
if #employer.update(employer_params)
redirect_to employer_path(#employer)
else
render 'edit'
end
end
def destroy
#employer.destroy
redirect_to root_path
end
private
def employer_params
params.require(:employer).permit(:paid, :name, :company, :position, :number, :email, :emp_img)
end
def find_employer
#employer = Employer.friendly.find(params[:id])
end
end
User model:
class User < ActiveRecord::Base
has_one :userinfo
has_one :employer
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
acts_as_messageable
after_create :welcome_send
def welcome_send
WelcomeMailer.welcome_send(self).deliver_now
end
end
Please let me know if you guys need more information.
I would use request.url() to get the URL of your view (the student profile url).
Try adding this to you view to get a feeling of it:
<%= debug("request.url: #{request.url()}") if Rails.env.development? %>
I hope this helps.
I am getting the following error while trying to delete a user in my Rails 4 App.
Pundit::NotAuthorizedError in UsersController#destroy
not allowed to destroy? this #<User:0x005595f691bd10>
Extracted source (around line #30):
#user = User.find(params[:id])
# debugger
authorize current_user
#user.destroy
redirect_to users_path, :notice => "User deleted."
end
I am giving the User Controller bellow :
class UsersController < ApplicationController
before_filter :authenticate_user!
before_action :set_menu
def index
#users = User.all.page(params[:page]).per(8)
authorize #users
end
def show
#user = User.find(params[:id])
authorize #user
end
def update
#user = User.find(params[:id])
#authorize #user
if #user.update_attributes(secure_params)
redirect_to users_path, :notice => "User updated."
else
redirect_to users_path, :alert => "Unable to update user."
end
end
def destroy
#user = User.find(params[:id])
authorize #user
#user.destroy
redirect_to users_path, :notice => "User deleted."
end
private
def secure_params
params.require(:user).permit(:role)
end
def set_menu
store_menu("User")
end
end
The bellow is my User Model Code
class User < ActiveRecord::Base
enum role: [:admin,:user]
after_initialize :set_default_role, :if => :new_record?
def set_default_role
self.role ||= :user
end
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_one :customer
# has_one :customer, dependent: :destroy
end
The bellow is my User policy file
class UserPolicy < ApplicationPolicy
attr_reader :user, :model
def initialize(user, model)
#user = user
#model = model
end
def index?
#user.admin?
end
class Scope < Scope
def resolve
scope
end
end
end
How to resolve the error on delete or destroy action of a particular user ?
You should be adding a method for delete in the user_policy.rb like below
def destroy?
current_user = #user
end
to get the destroy working.
I am using Devise gem in my Rails project. The reason I use Devise is because I want just logged in user can rate their teachers. Now, I get this error in my ratings_controller.rb although I already added user_id into my ratings and teachers table.
undefined method `current_user' for Teacher:0x00000004fcac48
#rating = #teacher.current_user.ratings.build
Here is my ratings_controller.rb:
class RatingsController < ApplicationController
def new
get_teacher
#rating = #teacher.current_user.ratings.build
end
def create
get_teacher
#rating = #teacher.current_user.ratings.create(rating_params)
if #rating.save
redirect_to school_teacher_path(#teacher.school, #teacher)
else
render 'new'
end
end
def destroy
get_teacher
#rating = #teacher.ratings.find(params[:id])
#rating.destroy
redirect_to school_teacher_path(#teacher.school, #teacher)
end
def get_teacher
#teacher = Teacher.find(params[:teacher_id])
end
private
def rating_params
params.require(:rating).permit(:easiness, :helpfulness, :clarity, :comment,
:teacher_id, :school_id)
end
end
rating.rb:
class Rating < ActiveRecord::Base
belongs_to :teacher
belongs_to :user
end
teacher.rb:
class Teacher < ActiveRecord::Base
belongs_to :school
has_many :ratings, dependent: :destroy
has_many :users
def name
"#{firstName} #{middleName} #{lastName}"
end
def to_s
name
end
end
user.rb:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :ratings
has_many :teachers
end
current_user is a controller helper, it's not a instance method of model.
you can add before_action :authenticate_user! in controller to make sure only logged in user can rate
You can change several code here. Before fixing your code, I suggest you to user before_action to make DRY code.
class RatingsController < ApplicationController
before_action :authenticate_user!
before_action :get_teacher
# your code #
private
def get_teacher
#teacher = Teacher.find(params[:teacher_id])
end
def rating_params
params.require(:rating).permit(:easiness, :helpfulness, :clarity, :comment, :teacher_id, :school_id)
end
end
Then, add before_action :authenticate_user! above before_action :get_teacher so you can get current_user in each method.
Finally, you have to fix your new and create method into this:
def new
#rating = current_user.ratings.build
end
def create
#rating = current_user.ratings.create(rating_params)
if #rating.save
redirect_to school_teacher_path(#teacher.school, #teacher)
else
render 'new'
end
end
You do not need to #teacher.current_user.ratings.create(rating_params) to get teacher_id because you have teacher_id in your rating_params. I hope this help you.
You need to build rating object for user like this:-
#rating = current_user.ratings.build
I'm using devise for my user auth and registration. I can register a user no problem. Im also using friendly. My issue is, I can only create one user profile.
The setup...
user.rb:
class User < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: :slugged
validates :name, uniqueness: true, presence: true
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_one :profile # each user should have just one profile
end
profile.rb:
class Profile < ActiveRecord::Base
belongs_to :user
end
profiles_controller.rb:
class ProfilesController < ApplicationController
before_action :authenticate_user!
before_action :only_current_user
def new
# form where a user can fill out their OWN profile
#user = User.friendly.find( params[:user_id] )
#profile = Profile.new
end
def create
#user = User.friendly.find( params[:user_id] )
#profile = #user.build_profile(profile_params)
if #profile.save # Not saving!!
flash[:success] = 'Profile Created!'
redirect_to user_path( params[:user_id] )
else
render action: :new # keeps rendering!
end
end
private
def profile_params
params.require(:profile).permit(:first_name, :last_name, :avatar, :job_title, :phone_number, :business_name)
end
end
Why is it that only one user can create a profile and not others? Is it has to do with the relations?
We use this setup with some of our apps - User -> Profile.
In short, you should build the profile at User creation. Then you can edit the profile as you need. Your problem of having a Profile.new method is very inefficient...
#app/models/user.rb
class User < ActiveRecord::Base
has_one :profile
before_create :build_profile #-> saves blank associated "Profile" object after user create
end
This will mean that each time a User is created, their corresponding Profile object is also appended to the db.
This will give you the capacity to edit the profile as required:
#config/routes.rb
resources :users, path_names: { edit: "profile", update: "profile" }, only: [:show, :edit, :update]
This will give you the opportunity to use the following:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :authenticate_user!, only: [:edit, :update]
before_action :authorize, only: [:edit, :update]
def show
#user = User.find params[:id]
end
def edit
#user = current_user
end
def update
#user = current_user
#user.update user_params
end
private
def authorize
id = params[:id]
redirect_to user_show_path(id) if current_user.id != id #-> authorization
end
def user_params
params.require(:user).permit(:x, :y, :z, profile_attributes: [:homepage, :other, :profile, :attributes])
end
end
The view/form would be the following:
#app/views/users/edit.html.erb
<%= form_for #user do |f| %>
<%= f.fields_for :profile do |f| %>
<%= f.text_field :homepage %>
...
<% end %>
<%= f.submit %>
<% end %>
In regards your current setup:
def new
#profile = current_user.profile.new
end
def create
#profile = current_user.profile.new profile_params
if #profile.save
redirect_to user_path(params[:id]), notice: "Profile Created!"
else
render action: :new
end
end
private
def profile_params
params.require(:profile).permit(:x, :y, :z)
end
Not sure why you don't create the profile in the after_create event of the user. As soon the user is created - create an empty (but associated) profile.
class User
has_one :profile, dependent: :destroy
after_create {
build_profile unless profile
profile.save
}
end
class Profile
belongs_to :user, autosave: true
end
so then, in your controller you just need the update method.
def update
if current_user.profile.update_attributes(user_params)
flash_it :success
return redirect_to edit_user_profile_path
else
flash_it :error
render :edit
end
end
I am using Devise for registration. But I want to build a profile for user so that where user can fill their info.
I want a single for profile for user but whenever new_profile_path another profile is created for that user, I want to avoid user to go to new_profile_path or create new profile after 1 profile is created.
here is the code
User.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_one :profile
has_many :statuses
end
profile.rb
class Profile < ActiveRecord::Base
belongs_to :user
validates_associated :user
end
profiles_controller.erb
class ProfilesController < ApplicationController
before_action :authenticate_user!
before_action :find_profile, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#profiles = Profile.all
end
def new
#profile = Profile.new
end
def create
#profile = Profile.new(profile_params)
#profile.user_id = current_user.id
#profile.save
respond_with(#profile)
end
def show
#profile = Profile.find(params[:id])
end
def edit
end
def update
#profile.update(profile_params)
respond_with(#profile)
end
private
def find_profile
#profile = Profile.find(params[:id])
end
def profile_params
params.require(:profile).permit(:first_name, :last_name, :birth_date,
:gender, :bio, :personal_website, :linkedin_profile, :facebook_profile,
:mobile_no, :telephone_no)
end
end
This is the current code for creating Profile for user. But every time a profile is created for user through new_profile_path. How can I avoid it?
Thanks in advance for giving your time.
One solution is:
# in User model
has_one :profile
before_create :build_profile, unless: :profile
Alternatively:
# in User model
has_one :profile
after_create :create_profile, unless: :profile
The conditional unless: :profile is there so that it doesn't overwrite a profile that was already added before the user was created.
When your using associations, you have to use build instead of new.... In your Profile controller...
def new
#profile = current_user.build_profile
end
def create
#profile = current_user.build_profile(profile_params)
if #profile.save
flash[:success] = "Profile saved"
redirect_to current_user_path
else
flash[:error] = "Error"
render: new
end
end
This will make sure that only one profile is created for each user...
def edit
#profile = current_user.profile.find(params[:id])
end
def update
#profile = current_user.profile.find(params[:id])
if #profile.update_attributes(profile_params)
flash[:success] = "Successfully updated" # Optional
redirect_to user_path
else
flash[:error] = "Error" # Optional
render :edit
end
end