No route matches {:locale=>:en, :action=>"email", :controller=>"games"} - ruby-on-rails

As I have written in the title I get the following error when I try to click on my games page.
This is what I have in my games_controller:
def email
respond_to do |format|
user = #game.user
email = user.email
g = GameTrade.game_interest(user)
g.deliver
format.html { redirect_to root_url }
format.json { render json: #game }
end
end
and this is what I have in the show.html.erb
<%= button_to "Send Email", :action => 'email'%>
in my routes page I do have the line resources :games

"email" is not a standard route for a resource, so you'll need to add a route for it. Ideally this would be a POST request, since following that link (button) causes changes to occur. Finally, you should really stick to using the url helpers rather than specifying actions as they make your code a little brittle.
Try something like this in your routes.rb:
resources :games do
post 'email', :on => :member
end
Then in your view, generate your button like so:
<%= button_to "Send Email", email_game_path(#game) %>
You'll then need to find the game in your email action in the usual way before you can do anything with it:
#game = Game.find(params[:id])

Related

Routing Error: No route matches [PUT] "/goals/4/edit"

I am trying to create a button to change a model record attribute from false to true. I'm using a form_tag as follows:
=form_tag edit_goal_path(goal), method: :post do
=hidden_field_tag :purchased, value: true
=submit_tag "Purchase"
It's haml, but feel free to post suggestions with ERB. I'm getting the following error:
No route matches [POST] "/goals/4/edit"
Rails.root: /home/ben/rails_projects/hartwig
However, I already have the following route from resources:
PUT /goals/:id(.:format) goals#update
My controller looks as following:
def edit
#goal = Goal.find(params[:id])
end
def update
#goal = Goal.find(params[:id])
if #goal.update_attributes(goal_params)
redirect_to '/goals', notice: "Update successful!"
else
render '/'
end
end
def goal_params
params.require(:goal).permit(:item, :description, :picture, :purchased)
end
How do I get this to work? Or is there a better way to solve this?
Your question says:
I am trying to create a button to change a model record attribute from false to true
so why are you using a form for it? I think a better approach would be to create a link or button that will call an ajax method or a normal method with post route and update your attribute. You can achieve it by following these steps:
a. Create a route for your custom action where you'll update your attribute:
post 'purchase_update/:id' => "goal#update_purchase", as: update_purchase #post as you want to send your goal id
b. create your custom method inside your controller:
def update_purchase
#goal = Goal.find(params[:id])
#goal.update_attribute(:purchased, true)
respond_to do |format|
format.html {redirect_to your_path, notice: 'purchase updated'}
format.js {} #if you want to do something by ajax
end
end
c. Create your link that will call this method:
=link_to "Purchase", update_purchase_path(#goal), method: post
and if you want to do it by ajax then
=link_to "Purchase", update_purchase_path(#goal), method: post, remote: true
Another solution to your problem could be adding a new method to the Goal Controller:
in goals_controller.rb
def purchase
#goal.update_attribute(:purchased, true)
end
and also add on top (just add :purchase)
before_action :set_goal, only: [:show, :edit, :update, :destroy, :purchase]
in routes.rb change to
resources :goals do
member do
post 'purchase'
end
end
to add a new post routes to your goals
now you will have a purchase_goal_path that you can use in your view like this:
link_to 'Purchase', purchase_goal_path(#goal), method: :post

Routing a post says missing template

I'm rather confused about this; I have a custom route here.
I have a groups/:id/new_caretaker. This has a form on it. Whenever that form is POSTed it should go to the same page; But to a different method.
However, if I post the form it says Missing template groups/create_caretaker, application/create_caretaker
How can I fix this?
Here's my form:
<%= form_tag(controller: "groups", action: "create_caretaker", method: "post") do %>
<div class="field">
<%= text_field_tag('email') %>
</div>
<%= submit_tag "Opslaan"%>
<% end %>
And my routes:
get "/groups/:id/new_caretaker" => "groups#new_caretaker", :as => :new_caretaker
post "/groups/:id/new_caretaker" => "groups#create_caretaker"
Added groups.controller methods:
Note: new_caretaker gets #group from a :before_action
def new_caretaker
end
def create_caretaker
email = params[:email]
if !email.blank?
userToAdd = User.find_by_email(email)
if userToAdd.blank?
#User doesn't exist
else
#User does exist
respond_to do |format|
if #group.users.find_by_id(userToAdd)
#theAlert = 'Deze gebruiker zit al in de groep en is niet toegevoegd'
format.html { render action: 'new_caretaker' }
format.json { render json: #theAlert, status: :unprocessable_entity }
else
#group.users << userToAdd
format.html { redirect_to #group, notice: 'De begeleider is toegevoegd.' }
end
end
end
end
end
The if !email.blank? => false and if userToAdd.blank? => true branches don't render or redirect. Therefor rails if looking for a template with the name of that action.
I'd suggest to enhance you routing editing routes.rb:
resources :groups do
member do
get 'new_caretaker'
post 'create_caretaker'
end
end
And then you call this redirect:
redirect_to group_new_caretaker_path(#group)
in the controller when needed.
This way, you'll also get a params[:group_id] param in the new_caretaker controller method to be able to handle group-related data (if needed).
The fix: I did not render anything in the if, just in the else. Some good tips in the answers though.

Rails 3: Using a link_to :action on an "index", isn't working

edit: The bug is that the feed_preference is always nil even after the link_to is pressed, so the (if feed_preference == nil) is always true. I still don't know what's causing this.
What this link_to is supposed to do:
When you press the link, it sorts the post index a certain way. One button sorts by trending value, another sorts by time, etc.
for some reason, in the function "make_feed_preference", the #user.feed_preference NEVER changes, even if i hard code it to #user.feed_preference = "foobar"
but it looks like redirect_to 'posts' is working fine.
<%= link_to displayIcon(1), {:action => :make_feed_preference, :id => current_user.id,
:preference => "trending value", :controller => "users"}, :method=>:post %>
in the users controller:
def make_feed_preference
#user = User.find(params[:id])
#user.feed_preference = params[:preference]
#user.save
redirect_to '/posts'
end
in the view for the posts index:
def index
#user = current_user
if #user.feed_preference == nil
#user.feed_preference = "trending value"
end
#posts = Post
unless #user.tag_list == []
#posts = Post.tagged_with(#user.tag_list, :match_all => :true)
end
if #user.feed_preference == "trending value"
#posts = #posts.order('trending_value DESC').page(params[:page]).per(5)
elsif #user.feed_preference == "time"
#posts = #posts.order('created_at DESC').page(params[:page]).per(5)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #posts }
end
end
Routes.rb
resources :users do
resources :comments
resources :posts
member do
get :following, :followers
end
collection do
post "tag_with"
post "clear_tag_list_and_preferences"
post "make_feed_preference"
end
end
Whenever I check the values, it's as if clicking the link_to does nothing.
You say it does nothing? The form doesn't even post?
If it's not posting at all... do you have your link_to in a form? If you are using the post method you have to have it in a form unless you are using something like the ujs jQuery libraries which use jQuery / Javascript to help with your 'post' operation.
Using the gem : gem 'jquery-rails'
https://github.com/indirect/jquery-rails
I would also like to see your 'rake routes'

How can I use a method action like the 'update', 'create' or 'destroy' actions (from scaffold)?

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

Use custom route upon model validation failure

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

Resources