I would like to DRY my controller as I use some snippets/blocks of code many times inside the same controller (I have removed some as it was too long but this already gives an idea of the repetition). Here are the blocks I keep repeating :
#deal = search_deal
#next_deal = find_next_deal
#userdeal = find_or_create_userdeal_participation
#user_credits = calculate_user_credits_in_deal
I'm quite rookie and don't know how to do this but I feel this code should be factorized.
class DealsController < ApplicationController
before_filter :find_deal,
:only => [ :showcase ]
before_filter :ensure_canonical_deal_path!,
:only => [ :showcase ]
def showcase
# find appropriate deal
#deal = search_deal
respond_to do |format|
format.html # showcase.html.erb
format.json { render json: #deal }
end
end
def buy_stuff
#deal = search_deal
# bring 'next deal' url to the view
#next_deal = find_next_deal
# USER IS SIGNED-IN
if user_signed_in?
#userdeal = find_or_create_userdeal_participation
#user_credits = calculate_user_credits_in_deal
# if: user still has credits available
if #user_credits >= 1
#do this
respond_to do |format|
format.js
end
else
respond_to do |format|
# do that
end
end
# USER IS NOT SIGNED-IN
else
respond_to do |format|
format.js { render :template => "deals/call_to_sign_in.js.erb" }
end
end
end
def show_discounts
#deal = search_deal
respond_to do |format|
#do that
end
end
def pending_deals
#deal = search_deal
# bring 'next deal' url to the view
#next_deal = find_next_deal
if user_signed_in?
#userdeal = find_or_create_userdeal_participation
#user_credits = calculate_user_credits_in_deal
end
respond_to do |format|
#do this
end
end
def ask_question
#deal = search_deal
respond_to do |format|
#do that
end
end
protected
def ensure_canonical_deal_path!
if request.path != actual_deal_page_path(#deal)
redirect_to actual_deal_page_path(#deal, :format => params[:format]), :status => :moved_permanently
return false
end
end
private
# DRY file as this is used multiple times
# trick source - http://blog.rstankov.com/rails-anti-pattern-setting-view-variables-in-before-actions/
def search_deal
Deal.friendly.find(params[:id])
end
def find_or_create_userdeal_participation
UserDeal.where('user_id = ? AND deal_id = ?', current_user.id, #deal.id).take ||
UserDeal.create(user_id: current_user.id, deal_id: #deal.id)
end
def calculate_user_credits_in_deal
current_user.credit_nb + #userdeal.history
end
def find_next_deal
Deal.order_next_deal_at(#deal).next
end
end
I think the best way to just add before_filters for those methods where you are calling repeat code like:
before_filter :search_deal, :only => [:showcase, :buy_stuff, ...]
class DealsController < ApplicationController
before_filter :find_deal, only: [:showcase]
before_filter :ensure_canonical_deal_path!, only: [:showcase]
def showcase
search_deal
respond_to do |format|
format.html
format.json{render json: #deal}
end
end
def buy_stuff
search_deal
find_next_deal
if user_signed_in?
find_or_create_userdeal_participation
calculate_user_credits_in_deal
if #user_credits >= 1
respond_to(&:js)
else
respond_to{|format| }
end
else
respond_to{|format| format.js{render template: "deals/call_to_sign_in.js.erb"}}
end
end
def show_discounts
search_deal
respond_to{|format|}
end
def pending_deals
search_deal
find_next_deal
if user_signed_in?
find_or_create_userdeal_participation
calculate_user_credits_in_deal
end
respond_to{|format| }
end
def ask_question
search_deal
respond_to{|format| }
end
protected def ensure_canonical_deal_path!
if request.path != actual_deal_page_path(#deal)
redirect_to actual_deal_page_path(#deal, format: params[:format]), status: :moved_permanently
return false
end
end
private def search_deal
#deal = Deal.friendly.find(params[:id])
end
private def find_or_create_userdeal_participation
#user_deal =
UserDeal.where('user_id = ? AND deal_id = ?', current_user.id, #deal.id).take ||
UserDeal.create(user_id: current_user.id, deal_id: #deal.id)
end
private def calculate_user_credits_in_deal
#user_credits = current_user.credit_nb + #userdeal.history
end
private def find_next_deal
#next_deal = Deal.order_next_deal_at(#deal).next
end
end
Related
I have a table DIM_STORE with columns STORE_ID, STORE_NAME, CLIENT_CODE, CREATE_TIMESTAMP, UPDATE_TIMESTAMP.
How to save a new record to oracle db in rails? STORE_ID, STORE_NAME and CLIENT_CODE are of varchar type. And I have a form through which I need to add a new store.
I am getting error as,
NoMethodError: undefined method \`returning_id?' for nil:NilClass: INSERT INTO "DIM_STORE" ("STORE_NAME", "STORE_ID", "CLIENT_CODE", "STORE_ID") VALUES (:a1, :a2, :a3, :a4)))
stores_controller.rb,
class StoresController < ApplicationController
protect_from_forgery with: :null_session, if: Proc.new {|c| c.request.format == 'application/json'}
before_filter :authenticate_user!, :is_admin
before_action :get_client
before_action :set_store, only: [:show, :edit, :update, :destroy]
# GET /stores
# GET /stores.json
def index
#stores = Store.where("CLIENT_CODE = ?", #client.client_code)
respond_to do |format|
if request.format == :json
format.json { render json: #stores.all}
else
format.js
format.html
end
end
end
# GET /stores/1
# GET /stores/1.json
def show
end
# GET /stores/new
def new
respond_to do |format|
#store = Store.new
format.js
format.html
end
end
def form
end
def new_store
end
# GET /stores/1/edit
def edit
end
# POST /stores
# POST /stores.json
def create
#store = Store.new(store_params)
#store.client_code = #client.client_code
puts #store
respond_to do |format|
if #store.save
format.js
else
format.js {render "stores/new"}
format.json {render json: #store.errors, status: :unprocessable_entity}
end
end
end
#GET /stores/create_success
def create_success
redirect_to request.referrer, notice: 'Store was successfully created under client.'
end
# PATCH/PUT /stores/1
# PATCH/PUT /stores/1.json
def update
respond_to do |format|
if #store.update(store_params)
format.js
else
format.js {render 'stores/edit'}
format.json {render json: #store.errors, status: :unprocessable_entity}
end
end
end
#GET /stores/update_success
def update_success
redirect_to request.referrer, notice: 'Store was successfully updated.'
end
# DELETE /stores/1
# DELETE /stores/1.json
def destroy
stores_users = #store.users
if stores_users.nil? || stores_users.empty?
#store.destroy
redirect_to request.referrer, notice: 'Store was successfully destroyed.'
else
redirect_to request.referrer, notice: 'Users still associated with store. Cannot delete store'
end
end
def get_client
#client = Client.friendly.find(params[:client_id])
puts #client.client_code
=begin
#client = Client.find_by_sql ["SELECT * FROM DIM_CLIENT WHERE client_code = ? ", params[:client_id]]
puts #client;
#client.each do |c|
#client_code = c[:client_code]
#client_name = c[:client_name]
end
puts #client_code
=end
=begin
#client.each do |c|
puts c[:client_code];
end
=end
=begin
#client = Client.find_by_sql ["SELECT client_code FROM DIM_CLIENT WHERE client_code = ? ", :client_code]
=end
end
private
def set_store
=begin
#store = Store.find_by_sql ["SELECT store_id FROM DIM_STORE WHERE store_id = ? ", params[:id]]
=end
#store = Store.friendly.find(params[:id])
end
def store_params
params.require(:store).permit(:store_name, :store_id, :client_code)
end
end
I am trying to create a session for a model called Commuter by defining a helper method in application_controller.rb file. As follows.
application_controller.rb
helper_method :current_commuter
def current_commuter
#commuter ||= Commuter.find session[:cid]
end
After verifying the commuter's phone number I am trying to create a
login session.
commuters_controller.rb
def verify
#commuter = Commuter.where(phone_number: params[:phone_number]).first
if (#commuter && #commuter.authenticate_otp(params[:otp],drift:300))
#commuter.auth_active = true
if #commuter.save
#Removed from session after verified it
session[:phone_number] = nil
session[:is_verified] = nil
#signed in commuter after verified it
sign_in(:commuter, #commuter)
flash[:notice] = "Your mobile no is verified."
end
else
flash[:alert] = "You have entered wrong otp.Please check again."
end
puts "#{current_commuter.phone_number}"
redirect_to root_path
end
I put a puts to check if the current_commuter is working or not. It is when I checked on the console. Now when I added few links on a view file as follows:
app/views/bookings/outstation.html.erb
<%if current_commuter.present? %>
<li> <%= link_to "Dashboard", dashboard_commuters_path %> </li>
<li> <%= link_to "Logout", destroy_commuter_session_path, method: :delete%></li>
<%else%>
<li>
<a href="" data-toggle="modal" data-target="#signinmodal">
REGISTER | LOGIN
</a>
</li>
<%end%>
Now I am getting the following error:
ActiveRecord::RecordNotFound in BookingsController#outstation
Couldn't find Commuter without an ID
EDIT
bookings_controller.rb
class BookingsController < ApplicationController
layout 'bookings'
before_action :set_ride_later_request_from_ref_id, only:[
:select_vehicle, :update_vehicle_details,
:contact_details,:complete_booking_request]
before_action :set_ride_later_request_from_uuid_ref, only:[
:request_quotations,:quotations, :confirm_booking,
:confirmation
]
before_action :set_trip_type, only: [:outstation, :local_booking]
def new_booking
#ride_later_request = RideLaterRequest.new
#vahicle = RideLaterRequest.new
end
def create_ride_later_request
#ride_later_request = RideLaterRequest.new(permitted_attributes(RideLaterRequest))
respond_to do |format|
if #ride_later_request.save
format.html {redirect_to bookings_select_vehicle_path(ref_id: #ride_later_request.rlr_ref_code.content)}
else
format.html {render :outstation}
end
end
end
def update_vehicle_details
respond_to do |format|
if #ride_later_request.update(permitted_attributes(RideLaterRequest))
format.html {redirect_to bookings_contact_details_path(ref_id:#ride_later_request.rlr_ref_code.content)}
else
format.html {render :select_vehicle}
end
end
end
def contact_details
end
def complete_booking_request
#operation = nil
if params[:get_otp].nil? && params[:get_quotations].nil?
render json:{error:"Wrongly formed request"}, status: 422
end
if params[:get_otp]
#operation = :get_otp
if #ride_later_request.update(permitted_attributes(RideLaterRequest))
SMSSender.send_otp_message(#ride_later_request.phone_number,#ride_later_request.otp_code)
return
else
render json:{error:#ride_later_request.errors.full_messages[0]}, status: 422
end
elsif params[:get_quotations]
#operation = :get_quotations
if (params[:ride_later_request][:otp].blank? ||
!#ride_later_request.authenticate_otp(params[:ride_later_request][:otp],drift:300))
render json:{error:"OTP is wrong"}, status: 422 and return
else
#ride_later_request.user_verified = true
if !#ride_later_request.save
render json:{error:#ride_later_request.errors.full_messages.first}, status:422 and return
end
if #ride_later_request.status == 'UnderConstruction'
render json:{error:"Some fields are missing. Please try again"}, status:422 and return
end
end
end
end
def request_quotations
request_loc = [#ride_later_request.pickup_lat,#ride_later_request.pickup_lng]
#rfq_agencies = #ride_later_request.rfq_agencies.sort_by{|l|l.distance_to(request_loc)}
#ride_later_quotes = #ride_later_request.ride_later_quotes.to_a
#ride_later_quotes.sort!{|a,b| a.total_payable.to_i <=> b.total_payable.to_i}
end
def quotations
#ride_later_quotes = #ride_later_request.ride_later_quotes.to_a
#ride_later_quotes.sort!{|a,b| a.total_payable.to_i <=> b.total_payable.to_i}
if session[:trip_type] == 'HourlyPackage'
render :local_booking_quotation
else
render :outstation_booking_quotations
end
end
def confirm_booking
if #ride_later_request.status=='Unfulfilled' ||
#ride_later_request.status=='Rejected' ||
#ride_later_request.status=='Ignored'
render json:{error:'Trip request has expired. Start a new booking.'}, status:422 and return
end
if #ride_later_request.status=="Cancelled"
render json:{error:'Trip request has been cancelled. Start a new booking.'}, status:422 and return
end
if #ride_later_request.status!="QuotesReady"
render json:{error:'Trip request is in wrong state. Start a new booking.'}, status:422 and return
end
#quote = #ride_later_request.ride_later_quotes.find(params[:quote_id]) rescue nil
if #quote.blank?
render json:{error:'Quotation not linked to this trip'}, status:422 and return
end
if #quote.status != 'Submitted'
render json:{error: "Quote is in wrong state #{#quote.status}. Start a new booking"}, status:422 and return
end
#quote.status = 'Accepted'
if !#quote.save
render json:{error:#quote.errors.full_messages.first}, status:422 and return
end
RideLaterRequestHandler.commuter_accepts_quote(#quote)
end
def confirmation
#ride = #ride_later_request.ride_later_ride
#quote = #ride.ride_later_quote
end
def set_ride_later_request_from_ref_id
#ref_id = params[:ref_id]
#ride_later_request = RlrRefCode.where(content:#ref_id).first.ride_later_request rescue nil unless #ref_id.blank?
if #ride_later_request.blank?
flash[:alert] = "Something went wrong. Please create new booking request."
redirect_to bookings_new_path
end
end
def set_ride_later_request_from_uuid_ref
#uuid = params[:booking_id]
#ride_later_request = RideLaterRequest.where(uuid_ref:#uuid).first rescue nil if #uuid.present?
if #ride_later_request.blank?
flash[:alert] = "Something went wrong. Please create new booking request."
redirect_to bookings_new_path
end
end
def select_vehicle
#ride_later_request = RlrRefCode.find_by_content(params[:ref_id]).ride_later_request
end
def vehicle_type_ac
if params[:booking_summary_id].present?
#ride_later_request = RideLaterRequest.find(params[:booking_summary_id])
else
#ride_later_request = RlrRefCode.find_by_content(params[:ride_later_request][:ref_id]).ride_later_request
#ride_later_request.update(vehicle_type: params[:ride_later_request][:vehicle_type], number_of_passengers: params[:ride_later_request][:number_of_passengers])
end
end
def vehicle_type
#ride_later_request = RlrRefCode.find_by_content(params[:ref_id]).ride_later_request
end
def outstation
#ride_later_request = RideLaterRequest.new(trip_type: 'Outstation')
end
def local_booking
#ride_later_request = RideLaterRequest.new(trip_type: params[:trip_type])
end
def bangalore_innova
#ride_later_request = RideLaterRequest.new(trip_type: 'Outstation')
end
def bangalore_outstation
#ride_later_request = RideLaterRequest.new(trip_type: 'Outstation')
end
def bangalore_taxi
#ride_later_request = RideLaterRequest.new(trip_type: 'Outstation')
end
def tt_for_rent
#ride_later_request = RideLaterRequest.new(trip_type: 'Outstation')
end
def minibus_for_rent
#ride_later_request = RideLaterRequest.new(trip_type: 'Outstation')
end
# def select_vehicle_local
# end
def about_us
end
def terms_conditions
end
def privacy_policy
end
def journey_way
#ride_later_request = RideLaterRequest.create(user_params)
#ride_later_request.save
respond_to do |format|
format.html {render :select_vehicle}
end
end
def outstation_booking_quotations
#ride_later_request = RideLaterRequest.find_by(id: params[:ride_later_request])
#ref_id = params[:ref_id]
end
def select_vehicle_outstation
#ride_later_request = RlrRefCode.find_by_content(params[:ref_id]).ride_later_request
redirect_to outstation_booking_quotations_path(#ride_later_request.rlr_ref_code.content, #ride_later_request )
end
def trip_summary
#ride_later_request = RlrRefCode.find_by_content(params[:ride_later_request][:ref_id]).ride_later_request
#ride_later_request.update(vehicle_type: params[:ride_later_request][:vehicle_type], number_of_passengers: params[:ride_later_request][:number_of_passengers])
puts "Ride LATER REQUEST LOG"
puts #ride_later_request
if #ride_later_request.update(additional_instructions: params[:ride_later_request][:additional_instructions], ac: 'AC')
render :template => 'bookings/booking_summary', :locals => {:ride_later_request => #ride_later_request, :ref_id => #ride_later_request.rlr_ref_code.content, :vehicle_type => params[:ride_later_request][:vehicle_type]}
else
format.html {render :index}
end
end
def user_params
params.require(:ride_later_request).permit(:pickup_area, :pickup_city, :destination_city, :pickup_lng, :pickup_lat)
end
def set_trip_type
session[:trip_type] = params[:trip_type]
end
end
It looks to me like the error's thrown here:
def current_commuter
#commuter ||= Commuter.find session[:cid]
end
Are you calling this as a before_action?
Using find raises an error if a record's not found, so I'd suggest you're either not passing in an id in session[:cid], or what you are passing doesn't match a Commuter in your db.
You can use find_by_id to avoid throwing an error (it returns nil if the record's not found), or work around this to ensure the method's only called where it should be.
Does that help?
Edit: Based on your additional info, this could be coming from any of the finds in the bookings_controller. Same explanation as above though :)
I'm using the pundit gem in order to give permissions to three different users(Admin, seller, viewer). Currently I got everything working, admin has access to everything, seller to his own products and viewer can just view the products.
The only glitch I'm having is that I would like the non signed_up/signed_in users to be able to view the products via search results. Right now non sign_up/signed_in users can see the search results but don't have access to the show view.
Here is the setup I have:
class ItemPolicy < ApplicationPolicy
attr_reader :item
def initialize(user, record)
super(user, record)
#user = user
#item = record
end
def update?
#user.is_a?(Admin) ? item.all : #user.items
end
def index?
#user.is_a?(Admin) ? item.all : #user.items
end
def show?
#user.is_a?(Admin) ? item.all : #user.items
end
def create?
#user.is_a?(Admin) ? item.all : #user.items
end
def new?
#user.is_a?(Admin) ? item.all : #user.items
end
def edit?
#user.is_a?(Admin) ? item.all : #user.items
end
def destroy?
#user.is_a?(Admin) ? item.all : #user.items
end
class Scope < Struct.new(:user, :scope)
def resolve
if user.is_a?(Admin)
scope.where(:parent_id => nil)
elsif user.is_a?(Seller)
scope.where(:id => user.items)
end
end
def show?
return true if user.is_a?(Admin)
return true if user.seller_id == seller.id && user.is_a?(Seller)
false
end
end
end
the controller:
class ItemsController < ApplicationController
before_action :set_item, only: [:show, :edit, :update, :destroy]
def index
authorize Item
#items = policy_scope(Item)
end
def search
if params[:term]
#items = Item.search(params[:term]).order("created_at DESC")
else
#items = []
end
end
def show
#comments = Comment.where(item_id: #item).order("created_at DESC")
#items = policy_scope(Item).find(params[:id])
authorize #item
end
def new
#item = Item.new
authorize #item
#categories = Category.order(:name)
end
def edit
authorize #item
#categories = Category.order(:name)
end
def create
#item = Item.new(item_params)
authorize #item
respond_to do |format|
if #item.save
format.html { redirect_to #item, notice: 'Item was successfully created.' }
format.json { render :show, status: :created, location: #item }
else
format.html { render :new }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
def update
authorize #item
respond_to do |format|
if #item.update(item_params)
format.html { redirect_to #item, notice: 'Item was successfully updated.' }
format.json { render :show, status: :ok, location: #item }
else
format.html { render :edit }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
def destroy
authorize #item
#item.destroy
respond_to do |format|
format.html { redirect_to items_url, notice: 'Item was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_item
#item = Item.find(params[:id])
authorize #item
end
def item_params
params.require(:item).permit(:title, :description, :image, :price, :category_id)
end
end
application_contoller.rb
class ApplicationController < ActionController::Base
include Pundit
protect_from_forgery prepend: true
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
def pundit_user
current_seller || current_admin || current_viewer
end
private
def user_not_authorized(exception)
policy_name = exception.policy.class.to_s.underscore
flash[:warning] = t "#{policy_name}.#{exception.query}", scope: "pundit", default: :default
redirect_to(request.referrer || root_path)
end
end
Update 1
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
raise Pundit::NotAuthorizedError, "must be logged in" unless user
#user = user
#record = record
end
def index?
true # anybody can view
end
def show?
true # anybody can view
end
def search?
index?
end
def new?
create?
end
def edit?
update?
end
def destroy?
update?
end
private
# don't repeat yourself
def admin?
user.is_a?(Admin)
end
def seller?
user.is_a?(Seller)
end
end
class ItemPolicy < ApplicationPolicy
attr_reader :item
class Scope < Struct.new(:user, :scope)
def resolve
if admin?
scope.where(parent_id: nil)
elsif seller?
# avoids a query for user.items
scope.where(seller: user)
end
end
end
def initialize(user, record)
super(user, record)
#user = user
#item = record
end
def update?
admin? || is_owner?
end
def create?
# just guessing here
admin? || seller?
end
private
def is_owner?
# or whatever the association between the item and its owner is
item.seller == user
end
end
You are confusing scopes and the authorization methods in Pundit. The new?, show? etc. methods should return a boolean indicating if the user is allowed to perform the action at all.
To allow unauthorized users to perform an action you simply return true.
Scopes are used to narrow down which records the user has access to. They only have a resolve method.
class ApplicationPolicy
# ...
private
# don't repeat yourself
def admin?
user.is_a?(Admin)
end
def seller?
user.is_a?(Seller)
end
end
class ItemPolicy < ApplicationPolicy
attr_reader :item
class Scope < Struct.new(:user, :scope)
def resolve
if admin?
scope.where(parent_id: nil)
elsif seller?
# avoids a query for user.items
scope.where(seller: user)
end
end
end
def initialize(user, record)
super(user, record)
#user = user
#item = record
end
def update?
admin? || is_owner?
end
def index?
true # anybody can view
end
def show?
true # anybody can view
end
def search?
index?
end
def create?
# just guessing here
admin? || seller?
end
def new?
create?
end
def edit?
update?
end
def destroy?
update?
end
private
def is_owner?
# or whatever the association between the item and its owner is
item.seller == user
end
end
Instead of repeating yourself (the conditions) you can shortcut many of the actions since the permissions for editing for example is the same as updating. You can even do this in the ApplicationPolicy so that you don't have to repeat it in each policy class:
class ApplicationPolicy
# ...
def index?
true # anybody can view
end
def show?
true # anybody can view
end
def search?
index?
end
def new?
create?
end
def edit?
update?
end
def destroy?
update?
end
private
# don't repeat yourself
def admin?
user.is_a?(Admin)
end
def seller?
user.is_a?(Seller)
end
end
class ItemPolicy < ApplicationPolicy
attr_reader :item
class Scope < Struct.new(:user, :scope)
def resolve
if admin?
scope.where(parent_id: nil)
elsif seller?
# avoids a query for user.items
scope.where(seller: user)
end
end
end
def initialize(user, record)
super(user, record)
#user = user
#item = record
end
def update?
admin? || is_owner?
end
def create?
# just guessing here
admin? || seller?
end
private
def is_owner?
# or whatever the association between the item and its owner is
item.seller == user
end
end
You are also authorizing the user twice at many places in your controller as it is as already performed by the set_item callback:
class ItemsController < ApplicationController
before_action :set_item, only: [:show, :edit, :update, :destroy]
def index
authorize Item
#items = policy_scope(Item)
end
def search
if params[:term]
#items = Item.search(params[:term]).order("created_at DESC")
else
#items = Item.none # Don't use [] as #items.none? for example would blow up.
end
end
def show
#comments = Comment.where(item_id: #item).order("created_at DESC")
authorize #item
end
def new
#item = authorize(Item.new)
#categories = Category.order(:name)
end
def edit
#categories = Category.order(:name)
end
def create
#item = authorize(Item.new(item_params))
respond_to do |format|
if #item.save
format.html { redirect_to #item, notice: 'Item was successfully created.' }
format.json { render :show, status: :created, location: #item }
else
format.html { render :new }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #item.update(item_params)
format.html { redirect_to #item, notice: 'Item was successfully updated.' }
format.json { render :show, status: :ok, location: #item }
else
format.html { render :edit }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
def destroy
#item.destroy
respond_to do |format|
format.html { redirect_to items_url, notice: 'Item was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_item
#item = authorize( Item.find(params[:id]) )
end
def item_params
params.require(:item).permit(:title, :description, :image, :price, :category_id)
end
end
So that multiple people can be an administrator to a business page, we've created a model called administration where people can apply to be an admin of a business and thus the status of "0" is "pending" and "1" is accepted.
How can I prevent users from editing a page where their status for i is still "0" (pending).
class Administration < ActiveRecord::Base
attr_accessible :business_id, :user_id, :status
belongs_to :user
belongs_to :business
scope :pending, where('status = ?',0).order("updated_at desc")
def self.new_by_user_business( user, business)
admin = self.new
admin.business_id = business.id
admin.user_id = user.id
admin.status = 0
admin.save!
end
end
Here is the current "edit page"
<h1>Editing business</h1>
<%= render 'form1' %>
Here is the business controller.
class BusinessesController < ApplicationController
respond_to :html, :xml, :json
before_filter :authenticate_user!, except: [:index, :show]
def index
#businesses = Business.all
respond_with(#businesses)
end
def show
#business = Business.find(params[:id])
if request.path != business_path(#business)
redirect_to #business, status: :moved_permanently
end
end
def new
#business = Business.new
3.times { #business.assets.build }
respond_with(#business)
end
def edit
#business = get_business(params[:id])
#avatar = #business.assets.count
#avatar = 3-#avatar
#avatar.times {#business.assets.build}
end
def create
#business = Business.new(params[:business])
if #business.save
redirect_to #business, notice: 'Business was successfully created.'
else
3.times { #business.assets.build }
render 'new'
end
end
def update
#business = get_business(params[:id])
if #business.update_attributes(params[:business])
flash[:notice] = "Successfully updated Business."
end
#avatar = #business.assets.count
#avatar = 3-#avatar
#avatar.times {#business.assets.build}
respond_with(#business)
end
def destroy
#business = get_business(params[:id])
#business.destroy
respond_with(#business)
end
def my_business
#business = Business.all
end
def business_tickets
#user = current_user
#business = get_business(params[:id])
#tickets = #business.tickets
#business_inbox = TicketReply.where(:email => #business.callred_email)
end
def your_business
#user = current_user
#business = get_business(params[:id])
if #business.users.map(&:id).include? current_user.id
redirect_to my_business_businesses_path, notice: 'You are already an administator of this business.'
else
#admin = Administration.new_by_user_business( #user, #business)
BusinessMailer.delay(queue: "is_your_business", priority: 20, run_at: 5.minutes.from_now).is_your_business(#user,#business)
redirect_to #business, notice: 'Thank you for claiming your business, and we will be in touch with you shortly.'
end
end
def view_message
# #business = Business.find(params[:business_id])
#ticket = Ticket.find(params[:id])
#reply = #ticket.ticket_replies
end
private
def get_business(business_id)
#business = Business.find(business_id)
end
end
You could add a before_filter to check the status. You will have to change some of the logic but this is the idea
class BusinessesController < ApplicationController
before_filter :restrict_access, :only => [:edit, :update]
private
def restrict_access
#business = get_business(params[:id])
redirect to root_path, :notice => "Not Authorized" unless current_user.status == 1
end
end
I upgraded to rails 4 and now I am no longer able to register users on my app. It seems like my gallery (carrierewave) has broken down. I have inspected the code and can't notice anything that would stop it from working now. I get a undefined method `galleries' and it points to def setup_gallery: self.galleries << Gallery.create and under def create: if #user.save
Fresh eyes on my code would be great.
Users controller:
class UsersController < ApplicationController
respond_to :html, :json
def settings
#user = User.find(id_params)
end
def new
#user = User.new
end
def profile
#profile = User.profile
end
def create
#user = User.new(user_params)
if #user.save
UserMailer.registration_confirmation(#user).deliver
session[:user_id] = #user.id
redirect_to root_url, notice: "Thank you for signing up!"
else
render "new"
end
end
def show
#user = User.find(id_params)
end
def edit
#user = User.find(id_params)
end
def index
#users = User.all
end
def destroy
User.find(id_params).destroy
flash[:success] = "User deleted."
redirect_to users_url
end
def update
#user = if current_user.has_role?(:admin)
User.find(id_params)
else
current_user
end
#user.update_attributes(user_params)
respond_with #user
end
private
def user_params
params.require(:user).permit(:name, :email, :username, :password, :zip_code, :birthday, :role)
end
def id_params
params.require(:id).permit(:name)
end
end
User model:
# models/user.rb
after_create :setup_gallery
def received_messages
Message.received_by(self)
end
def unread_messages?
unread_message_count > 0 ? true : false
end
def unread_messages
received_messages.where('read_at IS NULL')
end
def sent_messages
Message.sent_by(self)
end
# Returns the number of unread messages for this user
def unread_message_count
eval 'messages.count(:conditions => ["recipient_id = ? AND read_at IS NULL", self.user_id])'
end
def to_s; username
end
def has_role?(role_name)
role.present? && role.to_sym == role_name.to_sym
end
def send_password_reset
generate_token(:password_reset_token)
self.password_reset_sent_at = Time.zone.now
save!
UserMailer.password_reset(self).deliver
end
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
private
def setup_gallery
self.galleries << Gallery.create
end
end
photos controller:
class PhotosController < ApplicationController
def new
#photo = Photo.new
end
def create
#photo = Photo.new(photo_params)
#photo.user = current_user
if #photo.save
flash[:notice] = "Successfully created photos."
redirect_to :back
else
render :action => 'new'
end
end
def edit
#photo = Photo.find(id_params)
end
def update
#photo = Photo.find(id_params)
if #photo.update_attributes(photo_params)
flash[:notice] = "Successfully updated photo."
redirect_to #photo.gallery
else
render :action => 'edit'
end
end
def destroy
#photo = Photo.find(id_params)
#photo.destroy
flash
[:notice] = "Successfully destroyed photo."
redirect_to #photo.gallery
end
private
def user_params
params.require(:user).permit(:name)
end
def id_params
params.require(:id).permit(:name)
end
end
After some trial and error I found that I had to change the private method in the user model.
What works is,
Gallery.create(user: self)
Thanks for those who responded to help!