I have two models for users ; the Plans model has_many users. Now, what I would like to do is to allow users to upgrade/downgrade their plans, by changing the plan_id. I've set up a form, as well as the appropriate action, but when I hit submit, it doesn't seem to do what the PUT action says. It seems to use the update action.
Here's my form :
<%= form_tag("/users/update_plan", :method => "put" ) do %>
<%= hidden_field_tag :plan_id, plan.id %>
<%= submit_tag("Change To Plan", :class => "signup") %>
<% end %>
Here's my update action
def update_plan
#user = current_user
#user.plan_id = params[:plan_id]
#user.save
sign_in #user
redirect_to change_plan
end
When I submit the form above though, it not only doesn't register the change, but I think it uses the update action, and not the update_plan action. The reason I think this is because it redirects to the what's in the update action, and it flashes the same thing as the update action.
def update
#user = current_user
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in #user
redirect_to edit_user_path(#user)
else
render 'edit'
end
end
Here's my routes.rb file
Dentist::Application.routes.draw do
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :phones, only: [:new, :create, :destroy]
resources :find_numbers, only: [:new, :create, :destroy]
put 'users/update_plan'
match '/signup', to: 'users#new'
match '/login', to: 'sessions#new'
match '/signout', to: 'sessions#destroy', via: :delete
match '/change_plan', to: 'users#change_plan'
root to: 'static_pages#home'
match '/product_demo', to: 'static_pages#product_demo'
match '/pricing', to: 'plans#index'
match '/contact', to: 'static_pages#contact'
And here's a console screenshot of what's happening:
http://stepanp.com/debug3.jpg
It seems to say it's using the update_plan action, but... :S
Any help on trying to get Update_plan action to function would be greatly appreciated!
The form is going to the right place (/users/update_plan), but that is being routed to:
UsersController#update
as it says on the second line of your console log. So not the action you expect, and the problem is in your routes. Try this to list all your routes:
rake routes
Probably the users update route (created by resources :users) is catching this first:
PUT /users/:id(.:format) users#update
There are no restrictions on the content of id, and format is optional, so users/update_plan would call users/update with an id of update_plan (in fact you can see that is happening at the edge of your console log screenshot, look for the :id => parameter).
So I would move your custom route to the top of the routes file first above resources :users, and also try change it to direct to the action you want, not sure what a route with no action specified does...
put '/users/update_plan', to: 'users#update_plan'
Related
I have previewed all questions with similar topics and none of those solutions help me. I am attempting to create a twitter like feed that will display posts of a certain category in rails.
This is my industries controller:
class IndustriesController < ApplicationController
def index
#wads = Wad.order('created_at DESC')
end
def music
#music_wads = Wad.where(category: "Music").paginate(page: params[:page], per_page: 20)
#wad = #music_wads.pluck(:id)
end
end
This is part of my posts controller:
class WadsController < ApplicationController
before_action :find_wad, only: [:show, :edit, :update, :destroy]
def index
#wads = Wad.all
end
def show
#wad = Wad.find(params[:id])
end
def new
#wad = Wad.new
end
def create
#wad = current_user.wads.build(wad_params)
if #wad.save
redirect_to #wad
else
flash[:error] = 'Error try again'
render 'new'
end
end
end
And this is my show view for my industries controller:
<h1>Music Wads</h1>
<%= will_paginate #music_wads %>
<% #music_wads.each do |music_wad| %>
<%= link_to 'wads/:id' do %>
<div class="flex-rectangle">
<%= music_wad.user.name %>
<%= music_wad.short_form %>
<% end %>
</div>
<%= will_paginate #music_wads %>
<% end %>
Here is my routes file:
Rails.application.routes.draw do
root 'static_pages#home'
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
get '/signup', to: 'users#new'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
get '/industries', to: 'industries#index'
get '/music', to: 'industries#music'
get '/tech', to: 'industries#tech'
resources :users
resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]
resources :wads
end
I am attempting to make it so that clicking on a post among the lists of post carries you to page of that post (/wads/id). I've been baffled all day and am now at my wits end. I am aware I am a noob and this is a nooby question but any help would gladly be appreciated.
Thanks
resources :wads will create some routes that you can use.
Running rails routes (on rails 5) or rake routes (on rails 4 and lower) in the console will give you the list of your routes.
Under the prefix column you could find the correct route name you should use and under the URI Pattern you could see the actual address it links to.
You asked for wads/:id so the link should be <%= link_to wad_path(wad_music) do %> (the prefix is wad_path and you need to give it the object which holds the id - or an id...)
Since you want to link to a singular action - meaning that the action will get and id of an object - and get it (gets a single object!) the link prefix will be in singular form as well: wad_path and not wads_path
(wads_path will link to the index action in the controller and doesn't need to get any object or id)
I recently watched the railscast episode #250 Authentication from Scratch (revised) and I have the signup / login / logout actions working. However I am working on creating an action to delete a user from the database, but I am currently experiencing some errors when I try to delete a user.
The users_controller.rb delete / destroy actions look like the following,
def delete
# the below line calls the destroy method / action
self.destroy
end
def destroy
session[:user_id] = nil
# #user = User.find(params[:id])
#user.destroy
# User.find(parmas[:id]).destroy
# the below line didn't delete the current user :(
# #user = User.destroy
redirect_to :controller=>'users', :action => 'new'
end
The error message I'm getting in the browser when I try to delete a user looks like the following.
The page that contains the delete link looks like the following, index.html.erb
<h1>Welcome
<% if current_user %>
<%= current_user.email %>
<% end %>
</h1>
<p>You have <%= current_user.credit %> credits.</p>
<!-- http://stackoverflow.com/questions/5607155/ -->
<%= link_to('Delete your account', :controller => 'users', :action => 'destroy') %>
routes.rb
Rails.application.routes.draw do
# the below generated route is not necessary
# get 'sessions/new'
# delete user route
#get 'delete' => 'users#delete'
# shortened routes, per railscast comment
get 'signup' => 'users#new'
get 'login' => 'sessions#new'
get 'logout' => 'sessions#destroy'
# get 'signup', to: 'users#new', :as 'signup'
# get 'login', to: 'sessions#new', :as 'login'
# get 'logout', to: 'sessions#destroy', :as 'logout'
resources :users
resources :sessions
root to: 'users#new'
# get 'users/new'
# the below line specifies JSON as the default API format
namespace :api, defaults: {format: 'json'} do
namespace :v1 do
resources :users
end
end
It stands to reason you're getting a NoMethodError, since you've never set the #user variable, that line is commented out:
def destroy
session[:user_id] = nil
# #user = User.find(params[:id]) <-- Commenting out this line was your problem
#user.destroy
Changing to
def destroy
session[:user_id] = nil
#user = User.find(params[:id])
#user.destroy
You should be good to go.
EDIT: one thing you'd probably want to do is change from using the old style of link_to, specifying the controller and action, and change to the new style, using route helpers. In this case, you'd use, i believe, link_to 'Delete your account', current_user, :method => :delete, but you can check by running rake routes, where it will list the helpers available based on your routes.rb file.
Well, I think you should make things a bit simpler and start from the dummiest thing, that works. First of all, if you use your controller as a resource, there would not be a delete action there, only destroy.
def destroy
User.find(params[:id]).destroy
session[:user_id] = nil
redirect_to new_user_path
end
P.S. once again, I assume that you have set resources :users in your routes.rb.
If you have a bunch of get|post|put|delete routes instead, just make sure you point the redirect correctly.
i am fairly new to rails and want to keep the url the same for a user signing in if there is an error and the 'new' template is rendered
here are my routes
resources :users, only: [:new, :create]
resources :sessions, only: [:new, :create, :destroy]
root to: 'pages#home'
match '/signin', to: 'sessions#new'
#match '/signin', to: 'sessions#create', via: :post, as: :post_session
match '/logout', to: 'sessions#destroy'
and here is the sessions controller code
def new
end
def create
user = User.find_by_email(params[:session][:email])
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_to root_url
else
flash.now[:error] = 'Invalid email or password'
render 'new'
end
end
as you can see,i have a custom route commented out to catch the post so that the render 'new' call keeps the /signin url, but when i do this, the flash messaging of an error does not render in the page (it does without that route though). i tried to use flash without the now method and still was not seeing my message show up. any ideas?
EDIT:
i tried the suggestions below and was still seeing the issue. after looking at the access logs, the application was routing to the first signin route because it was defined with match and not get.
my updated and working routes file now looks like this
resources :users, only: [:new, :create]
#resources :sessions, only: [:new, :create, :destroy]
root to: 'pages#home'
match '/signin', to: 'sessions#new', via: :get
match '/signin', to: 'sessions#create', via: :post, as: :post_session
match '/logout', to: 'sessions#destroy', via: :delete
Take out the now, that shouldn't be needed. Your routes are probably conflicting. Based on how you have the match lines setup, you can probably just remove the resources :sessions altogether, and then uncomment the match line. That should take care of what you need.
Also, make sure to go back to your other questions and accept some answers. A 0% acceptance rate isnt as likely to attract answers.
Edit
Based on your comments, it might just not know what to render at this time when you removed the resources call. Try changing to:
render "sessions/new"
I'm working through Ryan Bates' Railscast #124: Beta Invitations. I've got all the code in place, but I haven't been able to actually get things working. When I try to send an invite email, I get this message.
Routing Error
No route matches [POST] "/invitations"
If I pluralize the resource's name in Routes.rb, I get a different routing error.
Routing Error
uninitialized constant InvitationsController
What am I doing wrong?
Here's my Routes.rb file.
resources :users, :invitation
resources :sessions, :only => [:new, :create, :destroy]
match '/hunts', :to => 'hunts#index'
match '/signup/', :to => 'users#new'
match '/signin', :to => 'sessions#new'
match '/signout', :to => 'sessions#destroy'
match '/contact', :to => 'pages#contact'
match '/about', :to => 'pages#about'
match '/help', :to => 'pages#help'
root :to => "pages#home"
match ':controller(/:action(/:id(.:format)))'
end
And my Invitation Controller.
class InvitationController < ApplicationController
def new
#invitation = Invitation.new
end
def create
#invitation = Invitation.new(params[:invitation])
#invitation.sender = current_user
if #invitation.save
if logged_in?
Mailer.deliver_invitation(#invitation, signup_url(#invitation.token))
flash[:notice] = "Thank you, invitation sent."
redirect_to root_path
else
flash[:notice] = "Thank you, we will notify when we are ready."
redirect_to root_path
end
else
render :action => 'new'
end
end
end
Update: Here's the info requested.
Views/invitation/html.erb
<%= form_for #invitation do |f| %>
<p>
<%= f.label :recipient_email, "Friend's email address" %><br />
<%= f.text_field :recipient_email %>
</p>
<p><%= f.submit "Invite!" %></p>
<% end %>
rake routes is a very useful tool which you can use to see all the routes defined for your application.
You have added resources :invitation which defines the following routes
invitation_index GET /invitation(.:format) invitation#index
POST /invitation(.:format) invitation#create
new_invitation GET /invitation/new(.:format) invitation#new
edit_invitation GET /invitation/:id/edit(.:format) invitation#edit
invitation GET /invitation/:id(.:format) invitation#show
PUT /invitation/:id(.:format) invitation#update
DELETE /invitation/:id(.:format) invitation#destroy
Note that you are calling the InvitationController's actions.
So nothing is wrong with your route -> controller mapping.
You are just posting to a non-existent route. When you pluralize the route's name, you end up having a non-existent controller (InvitationsController).
Just change the URL you're posting to and you're good to go.
Try to use the plural when you call resources in your config/routes.rb:
resources :users, :invitations
This happens because you pass an instance of the Invitation model (#invitation) to this helper, it pluralize the class name to know where to submit.
Moreover, since #invitation is not yet saved in the DB (#invitation.new_record? returns true) then form_for set the form's method to "POST".
This information means the POST request to 'invitations' is processed by "invitations#create" (The create method of the InvitationsController class). It's convention over configuration, if you want to access invitations in a RESTful way and use resources in your config/routes.rb things must be named in a certain way to work out of the box (or you could simply override the "action" attribute of your form using some of the form helpers options).
BTW if you want to make things in a different manner you should read the Rails Guide to Routing and see if some option can help you to define your invitations routing rules, and have a look at the REST chapter of the Getting Started Rails Guide.
UPDATE: I missed the sentence "If I pluralize the resource's name in Routes.rb, I get a different routing error."
BTW, the problem is your controller class name is "InvitationController" while the form generated by the form_for helper submit to "/invitations".
I cannot figure out why I am getting this error. I know this question is very similar to this question, but I have all the jquery links correct as verified by the fact that I can delete users without a problem but not the microposts. When I try the example in the browser and click the delete link(http://localhost:3000/microposts/253) on a micropost, even though the item does get deleted the browser says:
Routing Error
No route matches [GET] "/microposts/253"
Try running rake routes for more information on available routes.
Test result:
Micropost pages micropost destruction as correct user should delete a micropost
Failure/Error: expect { click_link "delete" }.should change(Micropost, :count).by(-1)
ActionController::RoutingError:
No route matches [GET] "/microposts/1"
routes.rb
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :microposts, only: [:create, :destroy]
match '/signup', to: 'users#new'
match '/signin', to: 'sessions#new'
match '/signout', to: 'sessions#destroy', via: :delete
match '/help', to: 'static_pages#help'
match '/about', to: 'static_pages#about'
match '/contact', to: 'static_pages#contact'
root to: 'static_pages#home'...
Microposts delete link:
<%= link_to "delete", micropost, method: :delete,
confirm: "You sure?",
title: micropost.content %>
Microposts controller:
class MicropostsController < ApplicationController
before_filter :signed_in_user, only: [:create, :destroy]
before_filter :correct_user, only: :destroy
def create
#micropost = current_user.microposts.build(params[:micropost])
if #micropost.save
flash[:success] = "Micropost created!"
redirect_to root_path
else
#feed_items = []
render 'static_pages/home'
end
end
def destroy
#micropost.destroy
redirect_back_or root_path
end
private
def correct_user
#micropost = current_user.microposts.find_by_id(params[:id])
redirect_to root_path if #micropost.nil?
end
end
I am unable to find the 3.2 tutorial repo to compare my sample_app to but I think I've followed the tutorial to the letter. Any help is appreciated.
Yes, The problem is that you haven't updated your routes. Inside your routes.rb file, you have resources :microposts, only: [:create, :destroy]. The route that its looking for is a :show to :microposts.
Without seeing your controller code, I suspect that after you delete the micropost, you are trying to redirect back to the micropost. Either update your route to this: resources :microposts, only: [:create, :destroy, :show] or post up the details of your microposts controller.
I had the same problem, and after restarting the rails server it worked fine for me.
[posting if anyone visits this page lately]
As I can see the problem is that your delete request goes as 'GET', But as per the REST conversions it should be a 'POST' request,
And I just created a sample app with Rails 3.1.3 and its delete link is as follows
In this case I have created a scaffold called User
<%= link_to 'Destroy', user, :confirm => 'Are you sure?', :method => :delete %>
You can check what is happening to your delete request by using Firebug with Firefox
I am working through the same tutorial, and am having the same problem. My analysis is that the problem is because we are using redirect_back_or root_path in the microposts controller (~/rails_projects/sample_app/app/controllers/microposts_controller.rb):
class MicropostsController < ApplicationController
...
before_filter :correct_user, only: :destroy
...
def destroy
#micropost.destroy
logger.debug "in MicropostsController.destroy:"
logger.debug " root_path=#{root_path}"
logger.debug " session[:return_to]=#{session[:return_to]}"
redirect_back_or root_path
end
The output from the logger.debug statements shown is:
in MicropostsController.destroy:
root_path=/
session[:return_to]=/microposts/28
Recall that redirect_back_or is defined in sessions_helper.rb as:
def redirect_back_or(default)
redirect_to(session[:return_to] || default)
clear_return_to
end
So, the call to redirect_back_or root_path will result in:
redirect_to(/microposts/28)
I'm a newbie here, but I think the default action is GET; at least, that's consistent with what I'm seeing, i.e. this is why we are posting a GET to /microposts/28.
Meanwhile, in routes.rb, we have defined the resource microposts to only support create and destroy actions:
resources :microposts, only: [:create, :destroy]
Of course, we don't want to GET the micropost we just deleted; we want to re-render (or re-direct?) back to the page from which we came. As evidence that this analysis is correct as far as it goes, I found that calling redirect_to root_path instead of redirect_back_or root_path "works", in that the micropost gets deleted (after popup confirmation), and puts the user back on the home page (showing the deleted micropost is gone).
I have now changed my as follows, so that the page from which the delete action was invoked re-appears:
def destroy
#micropost.destroy
redirect_to request.referer
end
I also changed my definition of SessionsHelper#store_location:
def store_location
session[:return_to] = request.fullpath if ['show', 'edit'].include?action_name
end
So, only 'show' and 'edit' actions attempt to resume after login.