NameError in UsersController#index uninitialized constant UsersController::User - ruby-on-rails

I'm new to Rails and continue getting this error. I've double checked my syntax and everything seems to be fine. I've included what I believe to be the pertinent files but let me know if you need more info.
controllers/users_controller.rb:
class UsersController < ApplicationController
def index
#users = User.all
render json: #users, status: :ok
end
def show
render json: #user
end
def create
#user = User.new(user_params)
#user.save
render json: #user, status: :created
end
def update
if #user.update(user_params)
render json: #user
else
render json: #user.errors, status: :unprocessable_entity
end
end
def destroy
#user = User.where(id: params[:id]).first
if #user.destroy
head(:ok)
else
head(:unprocessable_entity)
end
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:name, :email, :password)
end
end
models/user.rb
class User < ApplicationRecord
has_secure_password
validates :email, presence: true
has_many :reviews, :dependent => :destroy
has_many :albums
end
config/routes.rb
Rails.application.routes.draw do
root to: "static#home"
resources :users
get "*path", to: "fallback#index", constraints: ->(req) { !req.xhr? && req.format.html? }
end

The routes file is irrelevent here. It feels like the User model just cannot be found at all. Try just
User.new
in the console. If it can't be found perhaps the model is in the wrong location. e.g. is it in app/models/user.rb ? If it is what happens if you
require './app/models/user'
Anything like a syntax error, etc?

Related

Rails API Controller Update Action -- How to add many-to-many

I have a Rails Api that feeds a Vue front end. I have two main models, Contacts and Outlets, with a many to many relationship via a join table ContactOutlets. I am trying to figure out how in the Contacts controller to add an association to an outlet.
I recognize, I could call the ContactOutlet create action separately, but it seems wasteful if Rails can handle this on the back end. I want vue to call contact#update once.
Contact Model:
class Contact < ApplicationRecord
has_many :contact_outlets
has_many :outlets, through: :contact_outlets
has_many :calls
validates_uniqueness_of :email
validates_uniqueness_of :name
end
Outlet Model:
class Outlet < ApplicationRecord
has_many :contact_outlets
has_many :contacts, through: :contact_outlets
has_many :calls
validates_uniqueness_of :website
end
ContactOutlet:
class ContactOutlet < ApplicationRecord
belongs_to :contact
belongs_to :outlet
validates_uniqueness_of :contact_id, :scope => :outlet_id
end
Contacts Controller:
class ContactsController < ApplicationController
before_action :set_contact, only: %i[ show update destroy ]
# GET /contacts
def index
#contacts = Contact.all
render json: #contacts, include: :outlets
end
# GET /contacts/1
def show
render json: #contact, include: :outlets
end
# POST /contacts
def create
#contact = Contact.new(contact_params)
if #contact.save
render json: #contact, status: :created, location: #contact
else
render json: #contact.errors, status: :unprocessable_entity
end
end
# PATCH/PUT /contacts/1
def update
if #contact.update(contact_params)
render json: #contact, include: :outlets
else
render json: #contact.errors, status: :unprocessable_entity
end
end
# DELETE /contacts/1
def destroy
#contact.destroy
end
private
# Use callbacks to share common setup or constraints between actions.
def set_contact
#contact = Contact.find(params[:id])
end
# Only allow a list of trusted parameters through.
def contact_params
params.require(:contact).permit(:name, :email, :bio, :image_url)
end
end
Solved this. In case anyone else is looking the models above are fine. made some adjustments to the contact_params to allow access to the outlets array. Then fixed the update action. Full controller code below:
class ContactsController < ApplicationController
before_action :set_contact, only: %i[ show update destroy ]
# GET /contacts
def index
#contacts = Contact.all
render json: #contacts, include: :outlets
end
# GET /contacts/1
def show
render json: #contact, include: :outlets
end
# POST /contacts
def create
#contact = Contact.new(contact_params)
if #contact.save
render json: #contact, status: :created, location: #contact
else
render json: #contact.errors, status: :unprocessable_entity
end
end
# PATCH/PUT /contacts/1
def update
if #contact.outlets
#contact.outlets.delete_all
end
if params[:outlets]
contactOutlets = params[:outlets]
contactOutlets.each do |outlet|
#contact.outlets << Outlet.find(outlet[:key])
end
end
if #contact.update(contact_params)
render json: #contact, include: :outlets
else
render json: #contact.errors, status: :unprocessable_entity
end
end
# DELETE /contacts/1
def destroy
#contact.destroy
end
private
# Use callbacks to share common setup or constraints between actions.
def set_contact
#contact = Contact.find(params[:id])
end
# Only allow a list of trusted parameters through.
def contact_params
params.require(:contact).permit(:name, :email, :bio, :image_url, outlet_ids:[])
end
end

undefined method `total_pages' for #<Advertisement::ActiveRecord_Relation:0x007fe4cdd7df98>

I am trying to search through tags, and it was working fine. But after i started to use gem will_paginate for pagination, i can't do that because i am getting this error:
undefined method 'total_pages' for #<Advertisement::ActiveRecord_Relation:0x007fe4cdd7df98>
But if I search for an unknown tag it works fine (show an empty list of ads on index page).
advertisemts_controller.rb
class AdvertisementsController < ApplicationController
before_action :authenticate_user!
before_action :set_advertisement, only: %i[edit update destroy]
def index
#advertisements = Advertisement.paginate(page: params[:page],
per_page: 2)
end
def show
#advertisement = Advertisement.find(params[:id])
end
def new
#advertisement = Advertisement.new
end
def create
#advertisement = Advertisements::Create.call(advertisement_params)
if #advertisement.errors.blank?
redirect_to advertisement_path(#advertisement),
notice: 'The advertisement was successfully added.'
else
render action: 'new'
end
end
def update
if #advertisement.update(advertisement_params)
redirect_to #advertisement, notice: 'Advertisement was
successfully updated.'
else
render :edit
end
end
def destroy
#advertisement.destroy
redirect_to advertisements_path, notice: 'Advertisement was
successfully destroyed.'
end
private
def set_advertisement
#advertisement = current_user.advertisements.find(params[:id])
end
def advertisement_params
params
.require(:advertisement)
.permit(:title, :description, :user_id, :tags)
.merge(user_id: current_user.id)
end
end
search_queries_controller.rb
class SearchQueriesController < ApplicationController
def search_by_tag
#advertisements = Advertisement.find_by_tags(tags_params)
render 'advertisements/index'
end
private
def tags_params
params.fetch(:tags, '')
end
end
advertisement.rb
class Advertisement < ApplicationRecord
has_many :advertisement_tags, dependent: :destroy
has_many :comments
has_many :tags, through: :advertisement_tags
belongs_to :user
validates :title,
:description,
presence: true
def self.find_by_tags(tags)
Advertisement.joins(:tags).where('tags.tag_name IN (?)',
tags.split(/[\s,']/))
end
end
I don't know how to solve this problem, I am using ruby-2.3.4 and rails-5.1.2, will_paginate-3.1.
That's because
def search_by_tag
#advertisements = Advertisement.find_by_tags(tags_params)
render 'advertisements/index'
end
doesn't call paginate method on the relation, but renders the view which uses pagination.
You may even notice that Advertisement.all.paginate(page: 1).total_pages works, but Advertisement.all.total_pages doesn't.
Something like
def search_by_tag
#advertisements = Advertisement
.find_by_tags(tags_params)
.paginate(page: 1, per_page: 2)
render 'advertisements/index'
end
should fix the problem

How to send a mailer on update of an object in a HABTM join table

I have a User object and an Orgs object that are associated through a HABTM join table. I want to send an email to the users when the Orgs object is updated AND the Org.approved value is set to true. I have an approved boolean on the Org.
I think I've gotten most of the way there but I need help with the step of actually sending the email.
Here's my code
class OrgMailer < ApplicationMailer
default from: 'myemail#example.co'
def org_approved(user, org)
#user = user
#orgs = User.orgs.all
#url = 'http://example.com/login'
mail(to: #user.email, subject: 'Your listing has been approved.')
end
end
User.rb
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
has_and_belongs_to_many :orgs, join_table: :orgs_users
end
Org.rb
class Org < ApplicationRecord
has_and_belongs_to_many :users, join_table: :orgs_users
# after_update :send_approved_listing_email, only: [:update]
attachment :company_image
def send_approved_listing_email
OrgMailer.org_approved(i).deliver_now if org.approved === true
end
end
UPDATED: ADDED ORG_CONTROLLER
I've edited my code to look like the answer below but am now getting a new error: uninitialized constant Org::OrgsUser
It's caused when I hit the #org.users << #user line in the create action.
If I delete this line, I'm able to create an org but it's not associating properly.
org_controller.rb
class OrgsController < ApplicationController
before_action :set_org, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
def index
#orgs = Org.all
#tags = ActsAsTaggableOn::Tag.all
end
def show
end
def new
#org = Org.new
end
def contest
end
def edit
end
def create
#user = current_user
#org = Org.new(org_params)
#org.users << #user
respond_to do |format|
if #org.save
format.html { redirect_to thankyou_path, notice: 'Your listing was successfully created. Our team will approve your listing after review.' }
format.json { render :show, status: :created, location: #org }
else
format.html { render :new }
format.json { render json: #org.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #org.update(org_params)
format.html { redirect_to #org, notice: 'Listing was successfully updated.' }
format.json { render :show, status: :ok, location: #org }
else
format.html { render :edit }
format.json { render json: #org.errors, status: :unprocessable_entity }
end
end
end
def destroy
#org.destroy
respond_to do |format|
format.html { redirect_to orgs_url, notice: 'Listing was successfully destroyed.' }
format.json { head :no_content }
end
end
def tagged
if params[:tag].present?
#orgs = Org.tagged_with(params[:tag])
else
#orgs = Org.postall
end
end
private
def set_org
#org = Org.find(params[:id])
end
def org_params
params.require(:org).permit(:twitter, :linkedin, :facebook, :name, :offer, :offercode, :url, :descrption, :category, :approved, :company_image, :tag_list => [])
end
end
I'm using active admin for my admin panel and have a batch action to update any selected orgs and approve them. I think what I'm missing is that in the send_approved_listing_email method I need to iterate through the orgs and email each user when the org is approved.
Right now nothing happens on update so I'm sure I'm not doing this correctly. What am I missing? How should I write this?
I would create a model for the join table rather than using habtm. That way you can use a callback when the join object is saved:
class User < ApplicationRecord
has_many :orgs_users
has_many :orgs, through: :orgs_users
end
class Org < ApplicationRecord
has_many :orgs_users
has_many :users, through: :orgs_users
end
class OrgsUsers < ApplicationRecord
belongs_to :org
belongs_to :user
after_create :send_approved_listing_email
def send_approved_listing_email
OrgMailer.org_approved(user, org).deliver_now if org.approved === true
end
end

Rails 4: "Pundit::NotAuthorizedError"

In my Rails 4 app, there are 5 models:
class User < ActiveRecord::Base
has_many :administrations
has_many :calendars, through: :administrations
end
class Calendar < ActiveRecord::Base
has_many :administrations
has_many :users, through: :administrations
has_many :posts
end
class Administration < ActiveRecord::Base
belongs_to :user
belongs_to :calendar
end
class Post < ActiveRecord::Base
belongs_to :calendar
end
class Comment < ActiveRecord::Base
belongs_to :post
belongs_to :user
end
I implemented authentication with Devise (so we have access to current_user).
Now, I am trying to implement authorization with Pundit (first timer).
Following the documentation, I installed the gem and ran the rails g pundit:install generator.
Then, I created a CalendarPolicy, as follows:
class CalendarPolicy < ApplicationPolicy
attr_reader :user, :calendar
def initialize(user, calendar)
#user = user
#calendar = calendar
end
def index?
user.owner? || user.editor? || user.viewer?
end
def show?
user.owner? || user.editor? || user.viewer?
end
def update?
user.owner? || user.editor?
end
def edit?
user.owner? || user.editor?
end
def destroy?
user.owner?
end
end
I also updated my User model with the following methods:
def owner?
Administration.find_by(user_id: params[:user_id], calendar_id: params[:calendar_id]).role == "Owner"
end
def editor?
Administration.find_by(user_id: params[:user_id], calendar_id: params[:calendar_id]).role == "Editor"
end
def viewer?
Administration.find_by(user_id: params[:user_id], calendar_id: params[:calendar_id]).role == "Viewer"
end
I updated my CalendarsController actions with authorize #calendar, as follows:
def index
#user = current_user
#calendars = #user.calendars.all
end
# GET /calendars/1
# GET /calendars/1.json
def show
#user = current_user
#calendar = #user.calendars.find(params[:id])
authorize #calendar
end
# GET /calendars/new
def new
#user = current_user
#calendar = #user.calendars.new
authorize #calendar
end
# GET /calendars/1/edit
def edit
#user = current_user
authorize #calendar
end
# POST /calendars
# POST /calendars.json
def create
#user = current_user
#calendar = #user.calendars.create(calendar_params)
authorize #calendar
respond_to do |format|
if #calendar.save
current_user.set_default_role(#calendar.id, 'Owner')
format.html { redirect_to calendar_path(#calendar), notice: 'Calendar was successfully created.' }
format.json { render :show, status: :created, location: #calendar }
else
format.html { render :new }
format.json { render json: #calendar.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /calendars/1
# PATCH/PUT /calendars/1.json
def update
#user = current_user
#calendar = Calendar.find(params[:id])
authorize #calendar
respond_to do |format|
if #calendar.update(calendar_params)
format.html { redirect_to calendar_path(#calendar), notice: 'Calendar was successfully updated.' }
format.json { render :show, status: :ok, location: #calendar }
else
format.html { render :edit }
format.json { render json: #calendar.errors, status: :unprocessable_entity }
end
end
end
# DELETE /calendars/1
# DELETE /calendars/1.json
def destroy
#user = current_user
#calendar.destroy
authorize #calendar
respond_to do |format|
format.html { redirect_to calendars_url, notice: 'Calendar was successfully destroyed.' }
format.json { head :no_content }
end
end
And I included after_action :verify_authorized, :except => :index in my ApplicationController.
Now, when I log in, I can access http://localhost:3000/calendars/ but when I try to visit http://localhost:3000/calendars/new, I get the following error:
Pundit::NotAuthorizedError in CalendarsController#new
not allowed to new? this #<Calendar id: nil, name: nil, created_at: nil, updated_at: nil>
#user = current_user
#calendar = #user.calendars.new
authorize #calendar
end
Obviously, I must have done something wrong.
Problem: I can't figure out what.
Any idea?
You don't have access to the params in the model unless you pass them through. You should pass the calendar to the model instance function and you already have access to the user.
user.editor?(calendar)
def editor?(calendar)
Administration.find_by(user_id: self.id, calendar_id: calendar.id).role == "Editor"
end
The problem was that I had not defined a create action in the CalendarPolicy.
Since the CalendarPolicy inherits from the ApplicationPolicy — CalendarPolicy < ApplicationPolicy — and the create action in the ApplicationPolicy is set to false by default, I was getting an error.
Simply adding the following code to CalendarPolicy fixed the problem:
def create?
true
end
Bonus tip: there is no need to add a new action to CalendarPolicy since we already have the following code in ApplicationPolicy:
def new?
create?
end

Cancan restricting access to users when it shouldn't (Ruby on Rails)

I'm having problems with allowing admin users only to see and edit the users he created.
I have a tiered system: SuperUser > Admin > other users
My SuperUser can edit all users, but my Admin user can only edit himself. To try to fix this, I have a creator_id parameter that gives a creator_id to the new user that matches the id of the current user.
My controller for users:
class UsersController < ApplicationController
#CanCan resource will generate a 500 error if unauthorized
load_and_authorize_resource :user
# GET /users
# GET /users.json
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
# GET /users/1
# GET /users/1.json
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user }
end
end
# GET /users/new
# GET /users/new.json
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
#User.find(session[:user])
end
# POST /users
# POST /users.json
def create
#user = User.new(params[:user])
#user.creator = current_user
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'Registration successful.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.json
def update
#user = User.find(params[:id])
##user = current_user
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, notice: 'Successfully updated profile.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
end
and my ability.rb file:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new #Guest user w/o account
#Permissions on what pages can be seen by which users, and what
#Users can do with those pages
if user.status == "Super User"
can :manage, :all
elsif user.status == "Admin"
can :manage, Book
can [:create,:new], User
can [:show, :update], User, :id => user.id
can :manage, User, :creator_id => user.id
end
end
end
I did check the database, and it correctly assigns the current user's id to the creator_id of the new user. I'm just stuck. Cancan keeps denying the permission of updating those users and I'm not sure why. Any help is appreciated!
EDIT
My user model:
class User < ActiveRecord::Base
has_many :books
has_many :listings
has_many :orders
belongs_to :organizations
belongs_to :creator, class_name: 'User'
attr_accessible :password, :email, :first_name, :last_name, :password_confirmation, :status, :username
acts_as_authentic
validates :first_name, :presence => true
validates :last_name, :presence => true
validates :username, :presence => true, :uniqueness => true
validates :email, :presence => true, :uniqueness => true
validates :status, :presence => true
end
Okay just reading your question again it looks like you want an administrator to have authoritative access to manage a user. In this case you could define something fairly similar in your application_controller
def correct_user
if !params[:id].nil?
#user.User.find_by_id(params[:id])
if current_user.status :admin
else
access_denied unless current_user?(#user)
end
end
end
What this does is allows an administrator to have access to all users accounts and if the user is not an administrator then they are denied access. You can enable this feature using the before_filter in your controllers so that you could do something like before_filter :correct_user, :only => [:edit, :show] this means that only the correct user can have access to these actions. So should you have a UserController like the following maybe:
class UsersController < ApplicationController
load_and_authorize_resource
before_filter :correct_user, :only => [:edit, :show]
..
....
.....
end
This example shows that as a correct user or an admin will have access to edit and show actions.
Try this.
def initialize(user)
user ||= User.new
if user.super_user?
can :manage, :all
elsif user.admin?
can [:create, :new], User
can [:show, :edit, :update], User do |usr|
id == usr.id
end
can :manage, User do |usr|
usr.creator_id == usr.id
end
end
end
In user model, add methods:
def has_status?(given_status)
status == given_status
end
def admin?
has_status? 'Admin'
end
def super_user?
has_status? 'Super User'
end

Resources