Rails self-join gives an error - ruby-on-rails

I'm having troubles getting my friending model in Rails 4 working. I set up a friendship controller and modified my User model to use a self-join as follows.
Friendship Model:
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, class_name: "User", foreign_key: "friend_id"
validates_presence_of :user_id, :friend_id
end
User Model:
class User < ActiveRecord::Base
rolify
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :invitable, :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
has_many :items
has_many :friendships
end
My UserController:
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
before_filter :authenticate_user!
load_and_authorize_resource
def index
authorize! :index, #user, message: 'Not authorized as an administrator.'
#users = User.all
end
def update
authorize! :update, #user, message: 'Not authorized as an administrator.'
if #user.update_attributes(params[:user])
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
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit( :name, :email, :role_ids, :id, :user_id )
end
end
The relevant portion of my log:
NoMethodError - undefined method friends' for nil:NilClass:
app/views/users/index.html.erb:32:in_app_views_users_index_html_erb__2019584293611114470_70229529361660'
Unless I've missed this completely, I should be able to access a friend as #users.friends but that gives me a NoMethod Error. I've also tried accessing it as #users.friendships but I get the same error.
I have run the migration and restarted my rails server. I don't know what I'm missing but I would sure appreciate a fresh set of eyes. I think it must be something with how I've set up the model.

The models look fine, however in the index method on UsersController you have the following line: #users = User.all. This creates an array of users which means you can't call .friends on it. You need to access each user individually through iteration
#users.each do |user|
user.friends
# ... more code
end
or some other means.

Related

How can a user report another user?

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.

Rails Beginner NoMethodError in PinsController#new

having issues keep getting error undefined method `pins' for nil:NilClass, can someone explain how to fix this error. Been following a tutorial and recently got stuck.
pins_controller.rb
class PinsController < ApplicationController
before_action :find_pin, only: [:show, :edit, :update, :destroy]
def index
#pins = Pin.all.order("created_at DESC")
end
def new
#pin = current_user.pins.build
end
def create
#pin = current_user.pins.build(pin_params)
if #pin.save
redirect_to #pin, notice: "Successfully created new Pin"
else
render 'new'
end
end
def edit
end
def update
if #pin.update(pin_params)
redirect_to #pin, notice: "Pin was Successfully updated!"
else
render 'edit'
end
end
def destroy
#pin.destroy
redirect_to root_path
end
private
def pin_params
params.require(:pin).permit(:title, :description)
end
def find_pin
#pin = Pin.find(params[:id])
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 :pins
end
pin.rb
class Pin < ActiveRecord::Base
belongs_to :user
end
routes.rb
Rails.application.routes.draw do
devise_for :users
resources :pins
root "pins#index"
end
If you are using the gem Devise then the helper method current_user returns you the current logged in user in your session.
Pleases make sure a user is logged in/
You can make sure that the user is logged in by adding before_action :authenitcate_user! in your application controller(for all actions in your application).
If you are using devise, you might want to add
before_action :authenitcate_user!
method inside pins controller which ensures that the user is logged in.

Pundit Error with authorize #user in Rails 4 Application [Pundit::NotAuthorizedError in UsersController#destroy]

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.

Rails - Want to build a profile for user after using Devise gem as sign up

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

rails rotum object belonging to the user object

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

Resources