Im trying to make an app in Rails 4.
I am using Pundit (or trying to).
I have an application policy and an article policy.
Something isn't working. If I set my article policy for show? to be false, I expect not to be able to see the show page for articles. Instead, I can see the show page - I can't figure out what's wrong.
My application policy is:
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
#user = user
#record = record
end
def index?
false
end
def show?
scope.where(:id => record.id).exists?
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
def scope
Pundit.policy_scope!(user, record.class)
end
class Scope
attr_reader :user, :scope
def initialize(user, scope)
#user = user
#scope = scope
end
def resolve
scope
end
end
end
My article policy is:
class ArticlePolicy < ApplicationPolicy
def index?
true
end
def show?
false
# user.present?
end
def create?
user.present?
user && user.profile.addresses.exists?(address.id)
end
def update?
user && user.article.exists?(article.id) && user.article.created_at < 15.minutes.ago
# user.present? #&& user == article.user
end
def destroy?
# user.admin?
# user.present?
user && user.article.exists?(article.id)
end
private
def article
record
end
end
Can anyone see what I've done wrong?
Articles controller:
class ArticlesController < ApplicationController
before_action :set_article, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show, :search]
respond_to :html, :json
# GET /articles
# GET /articles.json
def index
query = params[:query].presence || "*"
#articles = Article.search(query)
end
# def index
# if params[:query].present?
# #books = Book.search(params[:query], page: params[:page])
# else
# #books = Book.all.page params[:page]
# end
# end
# GET /articles/1
# GET /articles/1.json
def show
end
# GET /articles/new
def new
#article = Article.new
#article.comments.build
end
# GET /articles/1/edit
def edit
end
# POST /articles
# POST /articles.json
def create
# before_action :authenticate_user!
# authorize #article
#article = Article.new(article_params)
respond_to do |format|
if #article.save
format.html { redirect_to(#article) }
format.json { render :show, status: :created, location: #article }
else
format.html { render :new }
format.json { render json: #article.errors, status: :unprocessable_entity }
end
end
end
def search
if params[:search].present?
#articless = Article.search(params[:search])
else
#articles = Articles.all
end
end
# PATCH/PUT /articles/1
# PATCH/PUT /articles/1.json
def update
# before_action :authenticate_user!
authorize #article
respond_to do |format|
# if #article.update(article_params)
# format.json { render :show, status: :ok, location: #article }
# else
# format.html { render :edit }
# format.json { render json: #article.errors, status: :unprocessable_entity }
# end
# end
if #article.update(article_params)
format.json { render :show, status: :ok, location: #article }
else
format.json { render json: #article.errors, status: :unprocessable_entity }
end
format.html { render :edit }
end
end
# DELETE /articles/1
# DELETE /articles/1.json
def destroy
before_action :authenticate_user!
authorize #article
#article.destroy
respond_to do |format|
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_article
#article = Article.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def article_params
params[:article].permit(:user_id, :body, :title, :image, :tag_list,
comment_attributes: [:opinion])
end
end
Related
everytime I submit a form here (that I scaffolded) localhost:3000/syllabus_requests/new
The rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
from my ApplicationController.rb file gets raised and I'm not sure why because in the policy class I have a create? method and it returns true
i'm using
ruby '2.3.1'
gem 'rails', '~> 5.0.0', '>= 5.0.0.1'
gem 'pundit', '~> 1.1'
I have a policy
class SyllabusRequestPolicy < ApplicationPolicy
attr_reader :current_user, :model
def initialize(current_user, model)
#current_user = current_user || User.new
#model = model #this is the syllabus_request record from the syllabus_requests table as a rails model object
end
def index?
#current_user.role == "admin"
end
def show?
#current_user.role == "admin"
end
def create?
true
end
def edit?
#current_user.role == "admin"
end
def update?
#current_user.role == "admin"
end
def destroy?
#current_user.role == "admin"
end
end
I have a controller
class SyllabusRequestsController < ApplicationController
before_action :set_syllabus_request, only: [:show, :edit, :update, :destroy]
# GET /syllabus_requests
# GET /syllabus_requests.json
def index
#syllabus_requests = SyllabusRequest.all
authorize #syllabus_requests
end
# GET /syllabus_requests/1
# GET /syllabus_requests/1.json
def show
authorize #syllabus_request
end
# GET /syllabus_requests/new
def new
#syllabus_request = SyllabusRequest.new
authorize #syllabus_request
end
# GET /syllabus_requests/1/edit
def edit
authorize #syllabus_request
end
# POST /syllabus_requests
# POST /syllabus_requests.json
def create
#syllabus_request = SyllabusRequest.new(syllabus_request_params)
authorize #syllabus_request
respond_to do |format|
if #syllabus_request.save
format.html { redirect_to #syllabus_request, notice: 'Syllabus request was successfully created.' }
format.json { render :show, status: :created, location: #syllabus_request }
else
format.html { render :new }
format.json { render json: #syllabus_request.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /syllabus_requests/1
# PATCH/PUT /syllabus_requests/1.json
def update
authorize #syllabus_request
respond_to do |format|
if #syllabus_request.update(syllabus_request_params)
format.html { redirect_to #syllabus_request, notice: 'Syllabus request was successfully updated.' }
format.json { render :show, status: :ok, location: #syllabus_request }
else
format.html { render :edit }
format.json { render json: #syllabus_request.errors, status: :unprocessable_entity }
end
end
end
# DELETE /syllabus_requests/1
# DELETE /syllabus_requests/1.json
def destroy
authorize #syllabus_request
#syllabus_request.destroy
respond_to do |format|
format.html { redirect_to syllabus_requests_url, notice: 'Syllabus request was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_syllabus_request
#syllabus_request = SyllabusRequest.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def syllabus_request_params
params.require(:syllabus_request).permit(:full_name, :email)
end
end
my ApplicationPolicy.rb file looks like this
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
#user = user
#record = record
end
def index?
false
end
def show?
scope.where(:id => record.id).exists?
end
def create?
binding.pry # this should not hit if I'm overriding it
false
end
def new?
binding.pry
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
def scope
Pundit.policy_scope!(user, record.class)
end
class Scope
attr_reader :user, :scope
def initialize(user, scope)
#user = user
#scope = scope
end
def resolve
scope
end
end
end
My ApplicationController.rb looks like this
include Pundit
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
devise_parameter_sanitizer.permit(:account_update, keys: [:name])
end
private
def user_not_authorized
# binding.pry
flash[:alert] = "You are not authorized to perform this action."
redirect_to(request.referrer || root_path)
end
end
Did you try to add a new? method in your SyllabusRequestPolicy ?
I have a model called Article in my rails 4 app.
I want to add a static page called foldaway.html.erb to my views/articles folder.
I have added that view page, and updated my articles controller with:
def foldway
end
I have also tried to exclude foldaway from the set_article method:
before_action :set_article, except: [:foldway], only: [:show, :edit, :update, :destroy ]
In my routes file I have added:
get '/foldway' => 'articles#foldway'
When I save all this and try to test if the page renders, I get an error that says:
Couldn't find Article with 'id'=foldway
Why is it trying to set the article id when I have excepted it from the set_article method in my rails controller. I just want it to render a static page.
How do I add this to my file?
My complete article controller is:
class ArticlesController < ApplicationController
before_action :set_article, except: [:foldway], only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show ]
layout "article"
respond_to :html, :json
# GET /articles
# GET /articles.json
def index
#articles = policy_scope(Article)
# query = params[:query].presence || "*"
# #articles = Article.search(query)
end
# def index
# if params[:query].present?
# #books = Book.search(params[:query], page: params[:page])
# else
# #books = Book.all.page params[:page]
# end
# end
# GET /articles/1
# GET /articles/1.json
def show
end
def foldway
end
# GET /articles/new
def new
#article = Article.new
#article.comments.build
end
# GET /articles/1/edit
def edit
authorize #article
end
# POST /articles
# POST /articles.json
def create
# before_action :authenticate_user!
# authorize #article
#article = current_user.articles.new(article_params)
respond_to do |format|
if #article.save
format.html { redirect_to(#article) }
format.json { render :show, status: :created, location: #article }
else
format.html { render :new }
format.json { render json: #article.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /articles/1
# PATCH/PUT /articles/1.json
def update
# before_action :authenticate_user!
authorize #article
respond_to do |format|
# if #article.update(article_params)
# format.json { render :show, status: :ok, location: #article }
# else
# format.html { render :edit }
# format.json { render json: #article.errors, status: :unprocessable_entity }
# end
# end
if #article.update(article_params)
format.html { redirect_to(#article) }
format.json { render :show, status: :ok, location: #article }
else
format.json { render json: #article.errors, status: :unprocessable_entity }
end
format.html { render :edit }
end
end
# DELETE /articles/1
# DELETE /articles/1.json
def destroy
before_action :authenticate_user!
authorize #article
#article.destroy
respond_to do |format|
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_article
#article = Article.find(params[:id])
authorize #article
end
# Never trust parameters from the scary internet, only allow the white list through.
def article_params
params.require(:article).permit(:body, :title, :image, :tag_list,
comment_attributes: [:opinion])
end
end
The problem is from your routes file.
I advise you tu put this inside your routes.rb file :
get 'articles/foldway' => 'articles#foldway', as: :foldway
match '/foldway', to: 'articles#foldway', via: :get
and for your articles controller you just have to put :
before_action :set_article, only: [:show, :edit, :update, :destroy ]
I have been using Rails scaffolds to build a Rails 4 app.
My current problem is set out below - which arrives when I try and render the articles new page in my app:
ActionController::UnknownFormat
It's referring to the create action in the articles controller (it extracts this error location):
#article = Article.new(article_params)
respond_to do |format|
if #article.save
format.json { render :show, status: :created, location: #article }
else
I have an articles controller with:
class ArticlesController < ApplicationController
before_action :set_article, only: [:show, :edit, :update, :destroy]
# respond_to :html
# GET /articles
# GET /articles.json
def index
#articles = Article.all
end
# GET /articles/1
# GET /articles/1.json
def show
end
# GET /articles/new
def new
#article = Article.new
end
# GET /articles/1/edit
def edit
end
# POST /articles
# POST /articles.json
def create
# before_action :authenticate_user!
# authorize #article
#article = Article.new(article_params)
respond_to do |format|
if #article.save
format.json { render :show, status: :created, location: #article }
else
format.html { render :new }
format.json { render json: #article.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /articles/1
# PATCH/PUT /articles/1.json
def update
before_action :authenticate_user!
authorize #article
respond_to do |format|
if #article.update(article_params)
format.json { render :show, status: :ok, location: #article }
else
format.html { render :edit }
format.json { render json: #article.errors, status: :unprocessable_entity }
end
end
end
# DELETE /articles/1
# DELETE /articles/1.json
def destroy
before_action :authenticate_user!
authorize #article
#article.destroy
respond_to do |format|
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_article
#article = Article.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def article_params
params[:article].permit(:body, :title, :image,
comment_attributes: [:opinion])
end
end
I have respond with html in the top line of the controller. I don't know why or what this does. I have read others problems which say you need to give it something to respond to, or use the responder gem. I don't want anything extraordinary - I just want the page to render.
Can anyone see what's wrong here?
It seems like you need a format.html so you can add this:
#article = Article.new(article_params)
respond_to do |format|
if #article.save
format.html { redirect_to(#article,
:notice => 'Article was successfully created.') }
format.json { render :show, status: :created, location: #article }
else
format.json { render :show, status: :created, location: #article }
end
end
I hope this help you.
If you aren't trying to do anything extraordinary, here's how I would clean up this controller:
class ArticlesController < ApplicationController
before_action :set_article, except: [:new, :create, :index]
def index
#articles = Article.all
end
def show
end
def new
#article = Article.new
end
def edit
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render :new
end
end
def update
if #article.update_attributes(article_params)
redirect_to #article
else
render :edit
end
end
def destroy
if #article.destroy
redirect_to articles_path
else
redirect_to #article
end
end
private
def set_article
#article = Article.find(params[:id])
end
def article_params
params[:article].permit(:body, :title, :image,
comment_attributes: [:opinion])
end
end
Note that I stripped out your authorization, so add it back in when everything is working.
I use cancan and devise, I can update delete and show but I can't create profile.
why I can't create new profile ("ActiveModel::ForbiddenAttributesError")
class Ability
include CanCan::Ability
def initialize(user)
if user.is_a?(Admin)
can :manage, :all
elsif user.is_a?(User)
can :read, Profile do |profile|
profile.try(:user) == user
end
can :update, Profile do |profile|
profile.try(:user) == user
end
can :destroy, Profile do |profile|
profile.try(:user) == user
end
can :create, Profile do |profile|
profile.try(:user) == user
else
can :read, :all
end
end
end
class ProfilesController < ApplicationController
before_action :set_profile, only: [:show, :edit, :update, :destroy]
load_and_authorize_resource
# GET /profiles
# GET /profiles.json
def index
user = User.find(params[:user_id])
#profiles = user.profiles
respond_to do |format|
format.html
format.xml {render :xml => #profiles}
end
end
# GET /profiles/1
# GET /profiles/1.json
def show
user = User.find(params[:user_id])
#profiles = user.profiles.find(params[:id])
respond_to do |format|
format.html
format.xml {render :xml => #profile}
end
end
# GET /profiles/new
def new
user = User.find(params[:user_id])
#profile = user.profiles.build
respond_to do |format|
format.html
format.xml {render :xml => #profile}
end
end
# GET /profiles/1/edit
def edit
user = User.find(params[:user_id])
#profiles = user.profiles.find(params[:id])
end
# POST /profiles
# POST /profiles.json
def create
user = User.find(params[:user_id])
#profile = user.profiles.create(profile_params)
respond_to do |format|
if #profile.save
format.html { redirect_to user_profiles_url, notice: 'Profile was successfully created.' }
format.json { render action: 'show', status: :created, location: #profile }
else
format.html { render action: 'new' }
format.json { render json: #profile.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /profiles/1
# PATCH/PUT /profiles/1.json
def update
user = User.find(params[:user_id])
#profiles = user.profiles.find(params[:id])
respond_to do |format|
if #profile.update(profile_params)
format.html { redirect_to user_profile_url, notice: 'Profile was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #profile.errors, status: :unprocessable_entity }
end
end
end
# DELETE /profiles/1
# DELETE /profiles/1.json
def destroy
user = User.find(params[:user_id])
#profiles = user.profiles.find(params[:id])
#profile.destroy
respond_to do |format|
format.html { redirect_to job_hunters_path }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_profile
#profile = Profile.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def profile_params
params.require(:profile).permit(:full_name, :phone_number, :email, :position, :years_of_experiance, :cover_letter, :resume, :reference)
end
end
If you already have load_and_authorize_resource in your controller code, you need to take another step in sanitizing your inputs via a create_params method call in your controller.
Here's a link to a useful resource
Firstly: your CanCan user ability can be re-written as follows:
can :create, :read, :update, :destroy, Profile, user_id: user.id
Secondly: your admin abilities should be written after your normal user abilities, thus overriding them more successfully:
def initialize(user)
# I prefer to alias CRUD actions to keep my ability files more succint
alias_action :create, :read, :update, :destroy, to: :crud
cannot :manage, :all #Failsafe
can :crud, Profile, user_id: user.id
... #additional abilities for user
if user.admin?
can :manage, :all #Override previous failsafe
Lastly: if your Profile class belongs_to a User, you ought to rewrite it as such. Thus, your profile_params would contain a user_id field.
If you were to follow that (correct) paradigm, your ProfilesController's #create action would look something like:
class ProfilesController < ApplicationController
load_and_authorize_resource
def create
#profile = Profile.new(profile_params)
if #profile.save
...
else
...
end
end
private
def profile_params
params.require(:profile).permit(:user_id, ...)
end
end
Good afternoon,
I've done a scaffold of a class, here the example: User - At the moment I was executing the test I saw this bug:
Minitest::Assertion: "User.count" didn't change by 1.
Expected: 3
Actual: 2
test/controllers/users_controller_test.rb:20:in `block in <class:UsersControllerTest>'
the refering code of the bug is this one:
test "should create user" do
assert_difference('User.count') do
post :create, user: { name: 'test', password: 'secret', password_confirmation: 'secret' }
end
assert_redirected_to user_path(assigns(:user))
end
So the code above was created by the scaffold, I just change the name reference.
UserController:
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy, :reset_password]
# GET /users
# GET /users.json
def index
#users = super
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: get_action_message }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
#user.update(user_params)
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: get_action_message }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: get_action_message }
format.json { head :no_content }
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, :password, :password_confirmation)
end
def search_params
super - ['password_digest']
end
def show_attributes
#show_attributes = super - ['password_digest']
end
end
UserModel
class User < ActiveRecord::Base
nilify_blanks
validates :name, presence: true, uniqueness: true;
has_secure_password
end
For what I was able to understand, the "create" it's not being executed. I've put the breakpoint on the Controller create but its not stoping there..
What am I doing wrong, besides my poor english skills?
Tks for the helping!!
Thks guys,
I found this bug.
I had forgotten to put in the user Session