Rails if conditional in controller error - ruby-on-rails

I'm wondering how can I print on the index of my project only the rooms with the :is_available column or the rooms table with the :true value (is boolean).
I can't figure out how to achieve this (Sorry but I'm new with Rails). Any advice will be very appreciate!
I've this error with my current code:
"ActiveRecord::RecordNotFound in RoomsController#home
Couldn't find Room without an ID"
Here is my rooms_controller code:
class RoomsController < ApplicationController
before_action :get_room, only: [:index, :home]
def index
end
def show
#room = Room.find(params[:id])
end
def home
if params[:set_locale]
redirect_to root_url(locale: params[:set_locale])
else
puts #rooms if Room.all(params[:is_available => :true])
end
end
def get_room
#rooms = Room.all
end
end

You already have got #rooms = Room.all, you just need to precise your query (from all to your is_available restriction).
def home
if params[:set_locale]
redirect_to root_url(locale: params[:set_locale])
else
puts #rooms.where(is_available: true)
end
end
Also, you should avoid using puts in your controller logic. Either pass variable to the view (you can change #rooms value or create new variable #available_rooms), respond_with it or log it using Rails.logger if you use puts as a debugging solution.

def index
end
def home
if params[:set_locale]
redirect_to root_url(locale: params[:set_locale])
elsif params[:is_available]
puts #rooms
end
end
def get_room
#rooms = Room.where(is_available: true)
end
Using puts in controller - not a good idea.Use view to show the data.

There are several issues you may have:
Routes
Your index method looks empty. I presume you're using "home" as a substitute
In this case, you have to know what type of action this is - a member or collection action? The reason this is important is that when you define your routes, you have to ensure you define the route in the right way. For your home route, I'd have done this:
#config/routes.rb
resources :rooms do
get "home", action: "home"
end
Scopes
You can use a scope to bring back all the values with :is_available present. This lives in the model like this:
#app/models/room.rb
Class Room < ActiveRecord::Base
scope :is_available?, -> { where(is_available: true) }
end
This will allow you to call
#room = Room.is_available?
Code
Although you've not given us any context of the error (when it happens, what you do to make it happen), this is what I would do to help fix it:
#app/controllers/rooms_controller.rb
def home
if params[:set_locale]
redirect_to root_url(locale: params[:set_locale])
else
puts Room.is_available?
end
end
This may change depending the params you send & how you send them

def home
if params[:set_locale]
redirect_to root_url(locale: params[:set_locale])
else
puts #rooms if params[:is_available] && Room.where(is_available: true)
end
end
should work.

Related

Devise: restricting page access using user attributes

Relatively new to rails, I've got a simple web app using Devise for user authentication. One attribute is an :admin boolean, set nil for most users, and I will change to true manually in the console for the few users who will need to have administrative access.
My question is: How should I restrict access to a particular page to those who have admin access marked as true?
I've attempted some of that logic in my pages_controller, but it doesn't seem to redirect me as desired (referring to the user_list section):
class PagesController < ApplicationController
before_action :authenticate_user!, :except => [:welcome]
def welcome
#code removed for brevity's sake
end
def dashboard
#ditto
end
def user_list
unless
current_user.admin == true
redirect_to pages_dashboard_path
else
#users = Users.all
end
end
end
Any suggestions on my goal of redirecting or otherwise restricting access to my user_list page would be greatly appreciated.
in your controller you can do something like this
class PagesController < ApplicationController
...
def user_list
if current_user.admin == true
#users = Users.all
else
render :not_an_admin
end
end
end
You can not send them to the same page that they dont have access
You can choose to render a new view
In your user_list method, model name should be singular.
def user_list
unless
current_user.admin == true
redirect_to pages_dashboard_path
else
#users = User.all
end
end

Creating a form for a different controller

I have several books that users can create and then create pages for them.
routes.rb:
resources :books do
member do
get 'pages'
end
end
This gives a link to create a new page through /books/:book_id/pages
In that page I render a partial:
<%= render '/pages/new' %>
book controller:
def page
#book = Book.find(params[:id])
#page = #book.pages.new
end
But when params are passed to a page controller the book_id is lost:
pages controller:
def create
#page = Page.new(params[:page])
if #page.save
redirect_to #page
else
render 'new'
end
end
Also error handling becomes difficult as after the redirect the id also disappears.
I believe rest of the application seems fine as when I create the page through console the book_id is preserved.
It is my first app so I'm not even sure if this is even the right way to approach it... How can I get this to work?
Thanks guys!
Nested resources can be handled in such a way.
# config/routes.rb
resources :books do
resources :pages
end
You can also restrict the actions being created by using only: [:index, :new] or except: [:destroy] on the resources call.
In your PagesController you would have the following params available.
GET /books/:book_id/pages/:id => creates a params[:book_id] and params[:id]
# app/controllers/pages_controller.rb
def create
#book = Book.find(params[:book_id])
#page = #book.pages.build(params[:page])
if #page.save
# ...
else
# ..
end
end
Note that the method call for building a new object through the association is #book.pages.build instead of .new. You'll find out all about Rails associations and how to build and create the objects through association in the Rails Guides on ActiveRecord associations. Hope these pointers help.
If you want to debug incoming parameters, you can just raise them as C404 suggested above.
# in any controller
def any_method
raise params.inspect
# or in yaml format
raise params.to_yaml
end
One way to debug this is to use "puts" in your controller for params to see what actually exists. "puts" are like println's in java or echo's in PHP
Please post the contents of params when ran with this code
def create
puts "params = #{params}"
#page = Page.new(params[:page])
if #page.save
redirect_to #page
else
render 'new'
end
end

Rails redirect based on user type

I'm learning Rails by building a shop application and I'm having a bit of trouble with redirects. I have 3 roles in the application:
Buyer
Seller
Administrator
Depending on which type they are logged in as then I would like to redirect to a different page/action but still show the same URL for each (http://.../my-account).
I don't like having to render partials in the same view, it just seems messy, is there another way to achieve this?
The only way I can think of is to have multiple actions (e.g. buyer, seller, administrator) in the accounts controller but that means the paths will look like http://.../my-account/buyer or http://.../my-account/seller etc.
Many thanks,
Roger
I've put my code below:
models/user.rb
class User < ActiveRecord::Base
def buyer?
return type == 'buyer'
end
def seller?
return type == 'seller'
end
def administrator?
return type == 'administrator'
end
...
end
controllers/accounts_controller.rb
class AccountsController < ApplicationController
def show
end
end
controllers/user_sessions_controller.rb
class UserSessionsController < ApplicationController
def new
#user_session = UserSession.new
end
def create
#user_session = UserSession.new(params[:user_session])
if #user_session.save
if session[:return_to].nil?
# I'm not sure how to handle this part if I want the URL to be the same for each.
redirect_to(account_path)
else
redirect_to(session[:return_to])
end
else
#user_session.errors.clear # Give as little feedback as possible to improve security.
flash[:notice] = 'We didn\'t recognise the email address or password you entered, please try again.'
render(:action => :new)
end
end
def destroy
current_user_session.destroy
current_basket.destroy
redirect_to(root_url, :notice => 'Sign out successful!')
end
end
config/routes.rb
match 'my-account' => 'accounts#show'
Many thanks,
Roger
In UserSessionsController#create (i.e.: the login method) you could continue to redirect to the account path (assuming that goes to AccountsController#show) and then render different views according to the role. I.e.: something like this:
class AccountsController < ApplicationController
def show
if current_user.buyer?
render 'accounts/buyer'
elsif current_user.seller?
render 'accounts/seller'
elsif current_user.administrator?
render 'accounts/administrator
end
end
end
Better yet, you could do this by convention...
class AccountsController < ApplicationController
def show
render "accounts/#{current_user.type}"
end
end
If I understand you question correctly, then the solution is simple.
You can just call the method you want inside your controller. I do this in my project:
def create
create_or_update
end
def update
create_or_update
end
def create_or_update
...
end
In your case it should be:
def action
if administrator? then
admin_action
elsif buyer? then
buyer_action
elseif seller? then
seller_action
else
some_error_action
end
end
You should probably explicitly call "render" with an action name in each of those actions, though.

Passing parameters into model

Rails 3.0.3
ruby 1.9.2p0
The Problem:
I have a Users table which has many items, the item(s) in turn therefore belongs to the Users.
In my model item.rb i attempt to save the item along with the value for the user.id so i have:
self.User_ID = #user.id
this however give me the error
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
this is causing some confusion that it can't find this as in the show.html.erb that 'wraps' this page <%= #user.id %> displays the correct ID on the page
Many thanks in advance
** EDIT **
The Shorten action is the action upon which i want to parameter to be passed
class ItemsController < ApplicationController
def redirect
#item = Item.find_by_shortened(params[:shortened])
if #item
#redirect_to #item.original
redirect_to #item.original
else
redirect_to :shorten
end
end
def shorten
#host = request.host_with_port
#user = current_user
You need to load the #user model in every action that will require access to it. Having it render properly in the show action will not guarantee it is loaded in the update action.
Usually you need to have something like this in your controller:
class UsersController < ApplicationController
before_filter :load_user, :except => [ :index, :new, :create ]
# ...
protected
def load_user
#user = User.find(params[:user_id] || params[:id])
rescue ActiveRecord::RecordNotFound
render(:text => 'Record not found')
end
end

Camping: Return user to recent entries, but keep errors

Users can view a specific entry in my webapp with a URL. /entry/8, for example. If an entry doesn't exist, "Entry not found" gets appended to #messages and I render an error page.
I'd like to show some arbitrary query instead of a blank page, but I can't figure out a good way to keep the error message around to be displayed. There are other actions that need to take place in the arbitrary query's controller, so I can't just duplicate the query and render :posts.
Some example code:
module MyApp::Controllers
class ComplexQuery < R '/query'
def get
#entries = Entries.all(:conditions => someComplexConditions)
until #entries.complexEnough? then #entries.makeMoreComplex! end
end
end
class SingleEntry < R '/entry/(\d+)'
def get(id)
#entries = Entries.find_all_by_id(id)
unless #entries.nil?
render :posts
else
#messages = ["That entry does not exist."]
render :blank # I want to run Controllers::ComplexQuery, instead of rendering a blank page.
end
end
end
end
Something like this?
def get(id)
#entries = Entries.find_all_by_id(id)
unless #entries.nil?
render :posts
else
r *MyApp.get(:ComplexQuery)
end
end
See Camping.method_missing.
But I would also recommend moving ComplexQuery into a helper method:
module MyApp::Helpers
def complex_query(conditions); end
end
Then you can complex_query(something) in both SingleEntry and ComplexQuery.
Try this:
#entry = Entry.find_by_id(params[:id]) # returns nil when not found
if #entry.nil?
flash[:notice] = "Entry not found"
render :action => "recent"
end

Resources