2 devise models (admin and user) and cancan - ruby-on-rails

This is my code but still it doesn't allow me to create profile from some resason.
I have 2 models, user and admin.
my controller:
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(:user_id, :full_name, :phone_number, :email, :position, :years_of_experiance, :cover_letter, :resume, :reference)
end
end
my cancan Ability:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.is_a?(Admin)
can :manage, :all
else 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
end
end
end
Error when I try to create is:
ActiveModel::ForbiddenAttributesError in ProfilesController#create

Try skip to load resource for :create action in your controller:
class ProfilesController < ApplicationController
before_action :set_profile, only: [:show, :edit, :update, :destroy]
load_and_authorize_resource
skip_load_resource :only => [:create]
#.....

You need to give access to both new and create actions. So, modify it accordingly as given. Hope it helps.
can [:new, :create], Profile
Apart from this make sure you have permitted all the params.
def profile_params
params.require(:profile).permit(:user_id, :full_name, :phone_number, :email, :position, :years_of_experiance, :cover_letter, :resume, :reference)
end

I manage to fix it. I use your skip_load_resource :only => [:create] and in ability:
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
else
cannot :read
cannot :destroy
cannot :create
end
end
end

Related

Rails Child id using parent id

My issue is, when I am under the camper show page
Current Camper URL:
campers/1
and I go to click on to view the appointment it uses the camper_id for the appointment_id which is wrong so say if the camper_id is 1 it will use the appointment_id as 1 and actually the appointment id is 3, so then it says Couldn't find appointment with id of 1.
Table Header
<% #appointments.each do |app| %>
<%= link_to app.camper.camperName, appointment_path(#camper, #appointment) %>
Campers Controller Show Action
#appointments = #camper.appointments
Camper Model
has_many :appointments, dependent: :destroy
Appointment Model
belongs_to :camper
Shallow Nested Routes File
resources :customers, shallow: :true do
resources :campers do
resources :appointments do
resources :orders do
member do
patch :complete
end
end
end
end
end
Camper Controller
class CampersController < ApplicationController
before_action :set_camper, only: [:show, :edit, :update, :destroy]
# before_action :set_customer, only: [:index, :new, :edit, :create, :update]
load_and_authorize_resource
# GET /campers
# GET /campers.json
def index
#campers = #customer.campers
end
def list
query = params[:q].presence || ""
#campers = Camper.search(query, page: params[:page], per_page: 20, order: {created_at: :desc} )
end
# GET /campers/1
# GET /campers/1.js
def show
#appointments = #camper.appointments
respond_to do |format|
format.html
format.json
end
end
# GET /campers/new
def new
#customer = Customer.find(params[:customer_id])
#camper = #customer.campers.build
end
# GET /campers/1/edit
def edit
end
def page_name
"Campers"
end
# POST /campers
# POST /campers.json
def create
#camper = Camper.new(camper_params)
respond_to do |format|
if #camper.save
format.html { redirect_to camper_path(#camper), notice: 'Camper was successfully created.' }
format.json { render :show, status: :created, location: #camper }
else
format.html { render :new }
format.json { render json: #camper.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /campers/1
# PATCH/PUT /campers/1.json
def update
respond_to do |format|
if #camper.update(camper_params)
format.html { redirect_to camper_path(#camper), notice: 'Camper was successfully updated.' }
format.json { render :show, status: :ok, location: #camper }
else
format.html { render :edit }
format.json { render json: #camper.errors, status: :unprocessable_entity }
end
end
end
# DELETE /campers/1
# DELETE /campers/1.json
def destroy
#camper.destroy
respond_to do |format|
format.html { redirect_to root_path, notice: 'Camper was successfully deleted.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_camper
#camper = Camper.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def camper_params
params.require(:camper).permit(:order_id, :customer_id, :year, :manufacturer, :modelName, :camperClass, :vin, :mileage, :notes, :user_id)
end
end
Appointments Controller
class AppointmentsController < ApplicationController
before_action :set_appointment, only: [:show, :edit, :update, :destroy]
# GET /appointments
# GET /appointments.json
def index
#camper = Camper.find(params[:camper_id])
#appointments = #camper.appointments
end
# GET /appointments/1
# GET /appointments/1.json
def show
#orders = #appointment.orders
end
# GET /appointments/newå
def new
#camper = Camper.find(params[:camper_id])
#appointment = #camper.appointments.build
end
# GET /appointments/1/edit
def edit
end
# POST /appointments
# POST /appointments.json
def create
#appointment = Appointment.new(appointment_params)
respond_to do |format|
if #appointment.save
format.html { redirect_to appointment_path(#appointment), notice: 'Appointment was successfully created.' }
format.json { render :show, status: :created, location: #appointment }
else
format.html { render :new }
format.json { render json: #appointment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /appointments/1
# PATCH/PUT /appointments/1.json
def update
respond_to do |format|
if #appointment.update(appointment_params)
format.html { redirect_to #appointment, notice: 'Appointment was successfully updated.' }
format.json { render :show, status: :ok, location: #appointment }
else
format.html { render :edit }
format.json { render json: #appointment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /appointments/1
# DELETE /appointments/1.json
def destroy
#appointment.destroy
respond_to do |format|
format.html { redirect_to camper_appointments_path(#appointment), notice: 'Appointment was successfully deleted.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_appointment
#appointment = Appointment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def appointment_params
params.require(:appointment).permit(:customer_id, :camper_id, :order_id, :title, :description, :date_in, :date_out)
end
end
appointment_path only takes a single appointment argument. Remove the #camper argument:
appointment_path(#appointment)

Rails form not redirecting to Show action

I have three models City, Area and User
In new user form after clicking on submit button server/app is not redirecting to show action
(my routes file config/routes)
Rails.application.routes.draw do
resources :areas
resources :cities
get 'users/update_cities'
resources :users
(user controller app/controllers/users_controller.rb )
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
def update_cities
#areas = Area.where("city_id = ?", params[:city_id])
respond_to do |format|
format.js
end
end
# GET /users
# GET /users.json
def index
#users = User.all
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
#user = User.new
#cities = City.all
#areas = Area.where("city_id = ?", City.first.id)
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
#user.area_ids = [params[:user][:area_id]]
format.html { redirect_to #user, notice: 'User was successfully created.' }
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
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
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: 'User was successfully destroyed.' }
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, :brief,:area_id)
end
end
and form (app/views/users/_form.html.erb)
(labels not included just to clean up d code a bit )
<%= form_for(#user, remote: true) do |f| %>
<%= f.text_field :name %>
<%= f.select :city_id, options_for_select(#cities.collect { |city|
[city.name.titleize, city.id] }), {include_blank: 'Select Something'}, { id: 'cities_select'} %>
<%= f.select :area_id, options_for_select(#areas.collect { |area|
[area.name.titleize, area.id] }, 0), {}, { id: 'areas_select' } %>
<%= f.submit %>
please help.. !
The remote: true parameter in your form is causing the problem. This setting is useful when you want to update/create an object, without updating the view you're in.
For more information you can check ruby on rails API

Edit model in has_many through relation

I want to edit a has_many through relation, but instead of editing the relation, it creates a new model.
In my form:
<%= form_for #service do |f| %>
<%= f.fields_for :service_users do |ac| %>
<% end %>
<% end %>
In my model:
class Service < ActiveRecord::Base
has_many :service_users
has_many :users, :through => :service_users
accepts_nested_attributes_for :service_users
end
Begin situation:
When i update the comments field:
After updating i see the edited relation as a duplication of the first one.
In some way i have to check if there're already relations present, but how?
Update:
My controller:
class ServicesController < ApplicationController
before_action :set_service, only: [:show, :edit, :update, :destroy, :users]
before_filter :authenticate_user!
# GET /services
# GET /services.json
def index
services = current_user.available_services
#available_services = services.group_by { |t| t.date.beginning_of_month }
end
# GET /services/1
# GET /services/1.json
def show
# service_users = current_user.service_users
#
# Service.find_each do |service|
# unless service_users.detect { |m| m.service_id == service.id }
# current_user.service_users.build service_id: service.id
# end
# end
#
#available_users = #service.available_users.group_by { |u| u.group }
#planned_users = #service.planned_users.group_by { |u| u.group }
#reserve_users = #service.reserve_users.group_by { |u| u.group }
end
# GET /services/new
def new
#service = Service.new
end
# GET /services/1/edit
def edit
#service.service_users.create
end
# POST /services
# POST /services.json
def create
#service = Service.new(service_params)
p service_params
respond_to do |format|
if #service.save
format.html { redirect_to #service, notice: 'Service was successfully created.' }
format.json { render action: 'show', status: :created, location: #service }
else
format.html { render action: 'new' }
format.json { render json: #service.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /services/1
# PATCH/PUT /services/1.json
def update
respond_to do |format|
p service_params[:service_users_attributes]
if #service.update(service_params)
format.html { redirect_to #service, notice: 'Service was successfully updated.' }
format.json { render action: 'show', status: :ok, location: #service }
else
format.html { render action: 'edit' }
format.json { render json: #service.errors, status: :unprocessable_entity }
end
end
end
def users
#users = #service.users
end
# DELETE /services/1
# DELETE /services/1.json
def destroy
#service.destroy
respond_to do |format|
format.html { redirect_to services_url }
format.json { head :no_content }
end
end
def destroy_association
if params[:id].present?
ServiceUser.find(params[:id]).delete
redirect_to root_path
end
end
def make_user_available_for_service
p '########'
p params
p #service
redirect_to root_path
end
private
# Use callbacks to share common setup or constraints between actions.
def set_service
#service = Service.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def service_params
params.require(:service).permit(:date, :comments,
service_users_attributes: [:user_id,
:service_id,
:availability,
:comments],
service_groups_attributes: [:service_id,
:group_id,
:start_time,
:end_time])
end
end
Try build instead of create.
Like this:
def edit
#service.service_users.build
end
And check your service_params.
Your missing an id for the service_users.

Creation working locally, but not on Heroku. ActiveRecord::UnknownAttributeError (unknown attribute: user_id)

Users can create guides only when they're logged in.
When I click on the 'New Guide' link, this is what Heroku's log puts out:
2013-12-30T20:28:37.826032+00:00 app[web.1]: ActiveRecord::UnknownAttributeError (unknown attribute: user_id):
GuidesController:
class GuidesController < ApplicationController
before_action :set_guide, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
# GET /guides
# GET /guides.json
def index
if params[:tag]
#guides = Guide.tagged_with(params[:tag])
else
#guides = Guide.all
end
end
# GET /guides/1
# GET /guides/1.json
def show
end
# GET /guides/new
def new
#guide = current_user.guides.build(guide_params)
end
# GET /guides/1/edit
def edit
end
# POST /guides
# POST /guides.json
def create
#guide = current_user.guides.build(guide_params)
respond_to do |format|
if #guide.save
format.html { redirect_to #guide, notice: 'Guide was successfully created.' }
format.json { render action: 'show', status: :created, location: #guide }
else
format.html { render action: 'new' }
format.json { render json: #guide.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /guides/1
# PATCH/PUT /guides/1.json
def update
respond_to do |format|
if #guide.update(guide_params)
format.html { redirect_to #guide, notice: 'Guide was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #guide.errors, status: :unprocessable_entity }
end
end
end
# DELETE /guides/1
# DELETE /guides/1.json
def destroy
#guide.destroy
respond_to do |format|
format.html { redirect_to guides_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_guide
#guide = Guide.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def guide_params
params.require(:guide).permit(:title, :author, :description, :link, :tag_list) if params[:guide]
end
end
You have this in your new action
def new
#guide = current_user.guides.build(guide_params)
end
Why? The new action should just return the form to the browser to create a new guide. You repeat this in your create action, where it should be.
Also your index has this:
def index
if params[:tag]
#guides = Guide.tagged_with(params[:tag])
else
#guides = Guide.all
end
end
You should probably be using guide_params[:tag] since the :tag is being returned by the browser.
EDIT I see you are using [:tag_list] in your whitelist. I assume you are handing that somewhere else? Have you tested the ability to do an index action with a tag defined? I think the only place you want to use bare params[:xxxx] is in a private method.

Undefined method 'find_by_targetable_id' rails activity

I've created an activity model and I'm trying to have it so that when a user deletes their activity it also deletes the corresponding status. I've been able to do it when deleting the status, it deletes the activity but not sure how to do it in the opposite direction. I tried finding the status by targetable_id but I get:
undefined method `find_by_targetable_id' for #<Class:0x8df4a70>
Parameters:
{"_method"=>"delete",
"authenticity_token"=>"s2wKOZxCBVarT5uge3AIFNXHepFuvNGM+kU/q+ArOjA=",
"id"=>"18"}
If you're familiar with the public_activity gem then targetable is the same thing as trackable and in this example, the activity id is 18 and it's corresponding status id is 53
ActivitiesController
class ActivitiesController < ApplicationController
before_filter :authenticate_member!, only: [:destroy]
before_filter :find_activity, only: [:destroy]
def index
following_ids = current_member.following_members.map(&:id)
#activities = Activity.where("member_id in (?)", following_ids.push(current_member.id)).order("created_at desc").all
end
def destroy
#status = Activity.targetable
if #status
#status.destroy
end
#activity.destroy
respond_to do |format|
format.html { redirect_to :back }
format.json { head :no_content }
end
end
private
def find_activity
#activity = current_member.activities.find(params[:id])
end
end
StatusesController
class StatusesController < ApplicationController
before_filter :authenticate_member!, only: [:new, :create, :edit, :update, :destroy]
before_filter :find_member
before_filter :find_status, only: [:edit, :update, :destroy, :show]
rescue_from ActiveRecord::RecordNotFound do
render file: 'public/404', status: 404, formats: [:html]
end
# GET /statuses
# GET /statuses.json
def index
#statuses = Status.order('created_at desc').all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #statuses }
end
end
# GET /statuses/1
# GET /statuses/1.json
def show
respond_to do |format|
format.html # show.html.erb
format.json { redirect_to profile_path(current_member) }
end
end
# GET /statuses/new
# GET /statuses/new.json
def new
#status = Status.new
#status.build_document
respond_to do |format|
format.html # new.html.erb
format.json { render json: #status }
end
end
# GET /statuses/1/edit
def edit
end
# POST /statuses
# POST /statuses.json
def create
#status = current_member.statuses.new(params[:status])
respond_to do |format|
if #status.save
current_member.create_activity(#status, 'created')
format.html { redirect_to :back }
format.json
else
format.html { redirect_to profile_path(current_member), alert: 'Post wasn\'t created. Please try again and ensure image attchments are under 10Mbs.' }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
# PUT /statuses/1
# PUT /statuses/1.json
def update
if params[:status] && params[:status].has_key?(:user_id)
params[:status].delete(:user_id)
end
respond_to do |format|
if #status.update_attributes(params[:status])
format.html { redirect_to profile_path(current_member), notice: 'Status was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
# DELETE /statuses/1
# DELETE /statuses/1.json
def destroy
#activity = Activity.find_by_targetable_id(params[:id])
if #activity
#activity.destroy
end
#status.destroy
respond_to do |format|
format.html { redirect_to :back }
format.json { head :no_content }
end
end
private
def find_member
#member = Member.find_by_user_name(params[:user_name])
end
def find_status
#status = current_member.statuses.find(params[:id])
end
def sortable_date
created_at
end
end
Should not this line
#status = Activity.targetable
be
#status = #activity.targetable
?
Second note: it probably will be better to move status destroying to Activity model before_destroy callback.

Resources