I'm creating a blog using Rails 3.2.5 and have been using link_to's to each action using the resource paths generated by Routes (i.e. for my code_entries: code_entries_path, new_code_entry_path, etc.) throughout the site. All of a sudden whenever I try to access a page I get this error:
undefined local variable or method `controller' for #<CodeEntriesController:0x007f887f8b3300>
This error is from my index action on my code_entries_controller.rb, but no matter which action I try to go to in any controller I get this error on every link_to with a Routes resource path. It was working fine before and I'm not sure what would have caused this.
Since this question is in the context of my code_entries, here is the code for code_entries_controller.rb, /code_entries/index.html.haml, routes.rb and the error I've been getting but in the context of the action code_entries#index:
code_entries_controller.rb
class CodeEntriesController < ApplicationController
before_filter :authenticate_action
def index
#entries = CodeEntry.order("created_at desc")
end
def new
#entry = CodeEntry.new
end
def show
#entry = CodeEntry.find_by_id(params[:id])
end
def create
#entry = CodeEntry.new(params[:code_entry])
if #entry.save
redirect_to code_entry_path(#entry), :notice => "#{#entry.title} has been created"
else
puts #entry.errors.messages.inspect
render "new"
end
end
def edit
#entry = CodeEntry.find_by_id(params[:id])
end
def update
#entry = CodeEntry.find_by_id(params[:id])
if #entry.update_attributes(params[:code_entry])
redirect_to code_entry_path(#entry), :notice => "#{#entry.title} has been updated"
else
puts #entry.errors.messages.inspect
render "edit"
end
end
def destroy
#entry = CodeEntry.find_by_id(params[:id])
#entry.destroy
redirect_to code_entries_path, :notice => "#{#entry.title} has been deleted"
end
end
/code_entries/index.html.haml
%h1 Hello!
%br
- #entries.each do |e|
%h2= link_to e.title, code_entry_path(e)
%h3= e.updated_at
= raw excerpt(e, 200)
%br
- if current_user
= link_to "Edit", edit_code_entry_path(e)
= button_to "Delete", code_entry_path(e), :confirm => "Really really?", :method => :delete
%hr
routes.rb
Blog::Application.routes.draw do
resources :users
resources :code_entries
resources :food_entries
resources :inclusive_entries
resources :sessions
root :to => "home#index"
get "login" => "sessions#new", :as => "login"
get "logout" => "sessions#destroy", :as => "logout"
get "users/new"
end
NameError in Code_entries#index
Showing /Users/kyle/Projects/blog/app/views/code_entries/index.html.haml where line #4 raised:
undefined local variable or method `controller' for #<CodeEntriesController:0x007f887f813418>
Extracted source (around line #4):
1: %h1 Hello!
2: %br
3: - #entries.each do |e|
4: %h2= link_to e.title, code_entry_path(e)
5: %h3= e.updated_at
6: = raw excerpt(e, 200)
7: %br
Rails.root: /Users/kyle/Projects/blog
Application Trace | Framework Trace | Full Trace
app/views/code_entries/index.html.haml:4:in `block in _app_views_code_entries_index_html_haml___3334012984247114074_70112115764360'
app/views/code_entries/index.html.haml:3:in `_app_views_code_entries_index_html_haml___3334012984247114074_70112115764360'
Request
Parameters:
None
Show session dump
Show env dump
Response
Headers:
None
I had made a method inside of application_controller.rb and used it as an argument with helper_method. Since it was inside of application_controller.rb and not application_helper.rb I had used the tag include ActionView::Helpers::UrlHelper so I could use a link_to inside the helper method. Somehow that include statement was making it blow up, but once I removed the include statement and moved the helper method into application_helper.rb everything turned out fine!
Related
I'm trying to insert the input from a select_tag to my controller method.
I've looked and cannot seem to resolve the issue.
This is the code I have below, nothing for the rank's selection comes up in the params at all.
<h1>hello please set <%= #user.username %>'s rank'</h1>
<%= select_tag 'rank', options_for_select(#ranks.collect{ |r| [r.rank_name] }) %>
<%= button_to "Update", :action => "set_user_rank_update", value: "#{#user.id}", method: :post %>
Update below with the controller and routes
Controller:
class Admin::RankController < ApplicationController
before_action :admin?
def new
#rank = Rank.new
end
def create
#rank = Rank.new(rank_params)
if params["rank"]["admin"].to_i == 1
#rank.toggle! :admin?
end
if #rank.save
flash[:success] = "Rank created"
redirect_to root_path
else
flash[:danger] = "Failed to create rank"
render 'new'
end
end
def set_user_rank_new
#user = User.find_by_id(params["format"])
#ranks = Rank.all
end
def set_user_rank_update
#user = User.find_by_id(params["value"])
#rank = Rank.find_by_id(params["rank"])
#rank_backup = #user.rank.first
debugger
#user.rank - #user.rank.first
#user.rank << #rank
if #user.rank.first == #rank
flash[:success] = "Set user's rank"
redirect_to root_path
else
flash[:danger] = "Failed to set user's rank"
#user.rank - #user.rank.first
#user.rank << #rank_backup
render 'set_user_rank_new'
end
end
private
def rank_params
params.require(:rank).permit(:rank_name, :rank_color)
end
end
Routes
Rails.application.routes.draw do
devise_for :users,
:controllers => { :registrations => "member/registrations" , :sessions => "member/sessions"}
scope module: 'public' do
root 'welcome#index'
end
scope module: 'member' do
get 'members/:id' => 'member#show'
end
scope module: 'admin' do
get 'rank/new' => 'rank#new'
post 'rank/create' => 'rank#create'
get 'rank/set_user_rank/new' => 'rank#set_user_rank_new'
post 'rank/set_user_rank/update' => 'rank#set_user_rank_update'
end
end
Try passing 2 element arrays to options_for_select. The way you have it looks like it would get you option text but no values, which could explain why it doesn't show up in the params.
So for example:
<%= select_tag 'rank', options_for_select(#ranks.collect{ |r|[r.rank_name, r.id] }) %>
The button_to helper creates an inline form with just the parameters included in the helper statement (in this case the user id).
You can check this by examining the resulting HTML on your page - which I think will show an input field for rank sitting outside the form tag.
To include the rank parameter, you should set up the form using a form helper and make sure the rank input is included inside the form.
For what purpose do you need it in your controller action?
With the link_to you can forwards params as well.
It would be very helpful to see your controller and also your routes.
I don't know an awful lot about Rails and I've inherited this project. For the past few days I've been trying to get my head around, 'link_to', and 'routes.rb'. This stuff is driving me mad - I've spent the whole day looking at it, pasting bits of code into bare projects, where it works..but I just don't understand the error I'm getting here, or how to go about solving it, so if you have any ideas....
In my page _signed_in_header.html.erb I have:
FAQ
In my routes.rb I have:
get "staticpages/faq"
I know this is set up correct, because when I start a sample project from scratch, it works.
But in this particular project I've inherited I get the error:
NoMethodError in Staticpages#faq
Showing /home/christophecompaq/Populisto/app/views/layouts/_signed_in_header.html.erb where line #48 raised:
undefined method `model_name' for NilClass:Class
Extracted source (around line #48):
45:
46: <div class='search-box'>
47: <%= simple_form_for #review, :url => search_index_path, :method => :post, :html => { :class => 'form-horizontal'} do |f| %>
48:
49: <%= f.input :search_ids, :collection => #data, :as => :grouped_chosen,
50: :group_method => :last, :prompt => false,
51: :input_html => { :class => 'span5', :multiple => true },
Trace of template inclusion: app/views/layouts/_header.html.erb, app/views/layouts/application.html.erb
Rails.root: /home/christophecompaq/Populisto
Application Trace | Framework Trace | Full Trace
app/views/layouts/_signed_in_header.html.erb:48:in `_app_views_layouts__signed_in_header_html_erb___586079249_69970641688720'
app/views/layouts/_header.html.erb:1:in `_app_views_layouts__header_html_erb__1905506502_69970640142220'
app/views/layouts/application.html.erb:21:in `_app_views_layouts_application_html_erb___1868096314_69970642536740'
Edit: I was asked to show my review controller code, so here it goes:
class ReviewsController < FrontEndController
respond_to :html, :json
before_filter :with_google_maps_api
def index
#review = Review.new
end
def create
#review = Review.create((params[:review] || {}).merge(:user_id => current_user.id))
if #review.save
redirect_to landing_page, :notice => I18n.t('write_review.review_successfully_created')
else
render :action => :index
end
end
def show
#review = Review.find(params[:id])
end
def edit
#review = Review.find(params[:id])
end
def update
#review = Review.find(params[:id])
if #review.update_attributes(params[:review])
else
render :edit
end
end
def destroy
#review = Review.find(params[:id])
#review.destroy
end
def repost
#review = Review.find(params[:id])
#review.repost(current_user)
end
def reject
#review = Review.find(params[:id])
current_user.reject #review
end
end
Anyway, if you have any ideas what could be wrong, I'd be delighted to know....Thanks.
Christophe.
in your route file, use this code
get "staticpages/faq", :as => 'faq_page'
The 'as' will generate 2 helper functions: faq_page_url and faq_page_path that you can use in your code
i hope this will help, i think we have the same issue but i've managed to fix this using this:
in my routes.rb
match 'pages/:action', :controller => "pages"
and in my view:
= link_to "About", {:controller => 'pages', :action => 'about'}
The error is happening during rendering of the layout template, not the controller view.
If you're testing the faq page you'll be hitting the StaticpagesController, not the ReviewController you pasted right? And presumably StaticpagesController does not set #review... hence your exception.
So either try wrapping the search box code in a conditional like:
<% if #review %>
... put your review search form here ...
<% end %>
or if the search is supposed to present on all pages, ensure it's populated on all pages. Maybe add a before_filter on your base controller class with something like
class ApplicationController < ....
before filter :ensure_review_set
private
def ensure_review_set
#review ||= Review.new
end
end
The search form is also referencing #data if the search_ids field. That will also need to be initialised by any controllers using this layout.
More generally, if your version of rails supports it, I'd very very highly recommend the better_errors gem for quickly debugging errors such as this.
In my Rails application, in routes.rb I have
match "show_fail" => "Posts#show_fail"
In posts_controller.rb:
def create
...
return redirect_to show_fail_path, :title => #post.title
end
def show_fail
end
In show_fail.html.erb:
Unsuccessful posting of post title <%= title %>
But I got an error undefined local variable or method 'title'. Why does it not know about the title variable, and how can I fix it?
redirect_to show_fail_path(:title => #post.title)
and take it from params[:title]
I made these changes appropriately:
Now in 'app/controllers/users_controller.rb' I have this code:
def reset
respond_to do |format|
format.html # reset.html.erb
end
end
def send_reset
respond_to do |format|
if #user.errors.empty?
...
else
format.html { render :action => 'reset' }
end
end
end
Now in 'config/routes.rb' I have this code:
resources :users do
collection do
get 'reset'
post 'reset'
get 'send_reset'
post 'send_reset'
end
end
If I submit the form ('app/views/users/reset.html.erb') related to changes
<%= form_tag( send_reset_users_path, :method => :post ) do %>
<%= text_field_tag :email %>
<%= submit_tag("Send") %>
<% end %>
the browser URL become '.../users/send_reset' but I want '.../users/reset' (I think the problem is around the 'format.html { render :action => 'reset' }' code that does not render correctly the action) or, maybe, the route.
In few words I aim to use the 'send_reset' action like I use, for example, the 'update', 'create' or 'destroy' actions (from scaffold), in my case that is without creating the 'app/views/users/send_reset.html.erb' file but just calling the action method to handle my issue. How can I make this?
The default Rails URL scheme is
:host/:controller/:action/:id
Rename your controller action from
def send_reset
end
to
def reset
end
and rename the views and routes to match this change.
However you are already using reset for get and send_reset for Post but you want them to be the same just do different things if you ask for the page or send a form POST.
def reset
case request.method
when :post
# send them an email
# redirect_to :somewhere_else
else # :get, :put, :delete
# render the view with the recovery form
end
end
I've just added a contact form to my Rails application so that site visitors can send me a message. The application has a Message resource and I've defined this custom route to make the URL nicer and more obvious:
map.contact '/contact', :controller => 'messages', :action => 'new'
How can I keep the URL as /contact when the model fails validation? At the moment the URL changes to /messages upon validation failure.
This is the create method in my messages_controller:
def create
#message = Message.new(params[:message])
if #message.save
flash[:notice] = 'Thanks for your message etc...'
redirect_to contact_path
else
render 'new', :layout => 'contact'
end
end
Thanks in advance.
One solution would be to make two conditional routes with the following code:
map.contact 'contact', :controller => 'messages', :action => 'new', :conditions => { :method => :get }
map.connect 'contact', :controller => 'messages', :action => 'create', :conditions => { :method => :post } # Notice we are using 'connect' here, not 'contact'! See bottom of answer for explanation
This will make all get request (direct requests etc.) use the 'new' action, and the post request the 'create' action. (There are two other types of requests: put and delete, but these are irrelevant here.)
Now, in the form where you are creating the message object change
<%= form_for #message do |f| %>
to
<%= form_for #message, :url => contact_url do |f| %>
(The form helper will automatically choose the post request type, because that is default when creating new objects.)
Should solve your troubles.
(This also won't cause the addressbar to flicker the other address. It never uses another address.)
.
Explanation why using connect is not a problem here
The map.name_of_route references JUST THE PATH. Therefore you don't need a new named route for the second route. You can use the original one, because the paths are the same. All the other options are used only when a new request reaches rails and it needs to know where to send it.
.
EDIT
If you think the extra routes make a bit of a mess (especially when you use it more often) you could create a special method to create them. This method isn't very beautiful (terrible variable names), but it should do the job.
def map.connect_different_actions_to_same_path(path, controller, request_types_with_actions) # Should really change the name...
first = true # There first route should be a named route
request_types_with_actions.each do |request, action|
route_name = first ? path : 'connect'
eval("map.#{route_name} '#{path}', :controller => '#{controller}', :action => '#{action}', :conditions => { :method => :#{request.to_s} }")
first = false
end
end
And then use it like this
map.connect_different_actions_to_same_path('contact', 'messages', {:get => 'new', :post => 'create'})
I prefer the original method though...
I just came up with a second solution, guided by Omar's comments on my first one.
If you write this as your resources route
map.resources :messages, :as => 'contact'
This gives (amongst others) the following routes
/contact # + GET = controller:messages action:index
/contact # + POST = controller:messages action:create
So when you move your 'new' action code into your 'index' action, you will have the same result. No flicker and an easier to read routes file. However, your controller will make no more sense.
I, however, think it is a worse solution because you'll soon forget why you put your 'new' code into the index action.
Btw. If you want to keep a kind of index action, you could do this
map.resources :messages, :as => 'contact', :collection => { :manage => :get }
This will give you the following route
manage_messages_path # = /contact/manage controller:messages action:manage
You could then move your index action code into the manage action.
I suspect you are posting to '/messages' from the form which creates the message which explains why you see that in your URL.
Any reason why this won't work:
def create
#message = Message.new(params[:message])
if #message.save
flash[:notice] = 'Thanks for your message etc...'
redirect_to contact_path
else
flash[:notice] = 'Sorry there was a problem with your message'
redirect_to contact_path
end
end
Not to my knowledge, no. Since im assuming you want to render so that you keep the #message object as is with the errors attached.
There is a horrible solution that I have which will let you do it, but, its so horrible, I wouldn't recommend it:
before_filter :find_message_in_session, :only => [:new]
def new
#message ||= Message.new
end
def create
#message = Message.new(params[:message])
if #message.save
flash[:notice] = 'Thanks for your message etc...'
redirect_to contact_path
else
flash[:notice] = 'Sorry there was a problem with your message'
store_message_in_session
redirect_to contact_path
end
end
private
def find_message_in_session
#message = session[:message]; session[:message] = nil
end
def store_message_in_session
session[:message] = #message
end