Routing Error - No route matches [POST] - ruby-on-rails

I have the following destroy method in my Tracks controller:
def destroy
if params[:product_id].present?
#product = Product.find(params[:product_id])
#track = #product.tracks.find(params[:id])
#track.destroy
redirect_to product_path(#product)
elsif params[:release_id].present?
#release = Release.find(params[:release_id])
#track = #release.tracks.find(params[:id])
#track.destroy
redirect_to release_path(#release)
end
end
I can destroy a Release Track using:
<%= link_to 'Destroy', release_track_path(#release,track), :confirm => 'Are you sure?', :method => :delete %>
But I get a routing error " No route matches [POST] "/products/74/tracks/43" " when I try to destroy Product Track:
<%= link_to 'Destroy', product_track_path(#product,track), :confirm => 'Are you sure?', :method => :destroy %>
I've taken a look at my Routes file and think it's probably an issue there, but having tried a few things i'm stumped! Can anyone help? This is driving me crazy. I'm using the same if els on my create method and it works fine for both Release Track and Product Track.
Here's my routes.rb (I suspect this is a big mess!)
Dashboard::Application.routes.draw do
get "home/index"
root :to => "home#index"
get "tracks/new"
get "tracks/create"
get "tracks/update"
get "tracks/edit"
get "tracks/destroy"
get "tracks/show"
get "tracks/index"
get "help/index"
resources :helps
resources :roles
resources :labels
devise_for :users
resources :users
resources :releases do
resources :artists
resources :tracks
resources :products do
resources :tracks
resources :itunes_data
end
end
resources :itunes_data
resources :tracks do
collection { post :sort }
end
resources :products do
resources :tracks
collection do
get 'schedulecsv'
get 'schedule'
get 'new_releases'
get 'active_lines'
get 'deleted_lines'
get 'gemsetup'
get 'amazonsetup'
get 'search'
end
end
resources :artists
end

You seem to have mixed up :delete and :destroy and the second line. :method expects an HTTP verb, so it should be :delete.

In order to manage your controllers in a much more maintainable way, you should really checkout the ressource_controller. It hides all the standard stuff away and lets you concentrate on the stuff you want to customize.

Related

How to destroy model with values

I'm kind of new to rails. I have a model called follows that has to values (requestor and following). I am having trouble creating a button that destroys a select model with two values
<dt>User ID:</dt>
<dd><%= #user.id %></dd>
<dt>User email:</dt>
<dd><%= #user.email %></dd>
<% if Follow.where(:requestor => current_user.id, :following =>#user.id).present? %>
<%= button_to 'Unfollow', follow_url, method: :delete, class: "text-danger", data: { confirm: 'Are you sure?' } %>
<% else %>
<%= button_to "Follow", {:controller => 'follows', :action => 'create', :requestor => current_user.id, :following => #user.id}, {:method => :post} %>
<% end %>
The Follow button below in the else statement works, but I cannot figure out how to get the destroy button to work. I'm executing these buttons on the User show page instead of on the follow index.
def destroy
#follow.destroy
respond_to do |format|
format.html { redirect_to follows_url, notice: 'Follow was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_follow
#follow = Follow.find(params[:id])
end
# Only allow a list of trusted parameters through.
def follow_params
params.permit(:requestor, :following)
end
def require_permission
if Follow.find(params[:id]).user != current_user
redirect_to goals_url, flash: { error: "You do not have permission to do that."}
end
end
end
I keep getting couldn't find Follow with 'id' error. It deletes sometimes, but the majority of the time I get this error.
Routes. uses general format
require 'sidekiq/web'
Rails.application.routes.draw do
resources :follows
resources :accounts
resources :goals
resources :retirements
get '/users', to: 'users#index'
get '/user/:id', to: 'users#show', as: 'user'
resources :calculate_debts
get '/privacy', to: 'home#privacy'
get '/terms', to: 'home#terms'
authenticate :user, lambda { |u| u.admin? } do
mount Sidekiq::Web => '/sidekiq'
end
resources :notifications, only: [:index]
resources :announcements, only: [:index]
devise_for :users, controllers: { omniauth_callbacks: "users/omniauth_callbacks" }
root to: 'home#index'
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
It deletes sometimes, but the majority of the time I get this error
If it works "sometimes" then my guess would be that you are not re-rendering your page after your delete, and you might end up clicking the "Unfollow" button twice on the same record, which will raise a RecordNotFound error like you showed.
Your html redirect seems fine but make sure you are also refreshing the page when the request is in json format.

Delete a row of data with a destroy button in Ruby

I have an index of all items from database listed in my view. I want to create a destroy button to destroy the current record in the database using Ruby on Rails 4. Here is my code:
<div>
<h1>All Incomes</h1>
<% #user_incomes.each do |income| %>
<div>
<p><%= income.title %></p>
<p><%= income.description %></p>
<p><%= number_to_currency(income.amount) %>
<p><%= income.user_id %></p>
<%= button_to "Destroy", {action: "destroy", id: income.id}, method: :destroy, data: { confirm: "Are you sure?" } %>
</div>
<br />
<%end%>
</div>
My Income Controller:
class IncomesController < ApplicationController
before_action :authorize, only: [:new, :index, :show, :create]
def index
#incomes = Income.all #income refers to the db model income
#user_incomes = Income.all.where(:user_id=>current_user.id)
end
def show
#income = Income.find(params[:id])
end
def new
#income = Income.new
end
def create
#income = Income.create(income_params)
end
def destroy
#income.destroy
end
## Strong Parameters alias Rails 3's attr_accessible
private
def income_params
params.require(:income).permit(:title, :user_id, :description, :type, :amount)
end
def declare_income
#income = Income.find(params[:id])
end
end
Here is my route file:
Rails.application.routes.draw do
get 'member_content/new'
#get 'sessions/new' ## this is generated with rails g controller sessions new
resources :sessions
resources :incomes
resources :users
resources :abl_deductions
get 'main/index'
# Example of regular route:
# get 'products/:id' => 'catalog#view'
get 'signup', to: 'users#new', as: 'signup'
get 'login', to: 'sessions#new', as: 'login'
get 'logout', to: 'sessions#destroy', as: 'logout'
get 'content', to: 'member_content#new', as: 'content'
get 'add_income', to: 'incomes#new', as: 'add_income'
get 'add_deduction', to: 'abl_deductions#new', as: 'add_deduction'
get 'deductions', to: 'abl_deductions#index', as: 'deductions'
end
I am newb to rails, would it be easier for this action if I had use a scaffold with rails generate scaffold?
Let's assume your controller is called IncomesController. When you run bin/rails routes in your app folder, you should also see something like:
DELETE /incomes/:id(.:format) incomes#destroy
To achieve this, you need to have proper routes.rb records. Easy thing to achieve standard CRUD operations over incomes is to have resources :incomes in routes.rb
You also need to have destroy method in IncomesController to perform actual destroy.

Rails[Devise]: devise breaking navbar links

I have a Bootstrap navbar, but the tabs are generated at runtime. It's this way because they link to show/:id and a user can delete the record associated with that tab at any time. I created the links like this:
<% #groups.each do |group| %>
<li id=<%= group.id %>><%= link_to t("navbar." + group.name.singularize.downcase), :controller => 'groups', :action => 'show', :id => group.id %></li>
<% end %>
This works fine until I use Devise and attempt to get to /admins/sign_in. The navbar code is still exactly the same, but I get an UrlGenerationError:
No route matches {:action=>"show", :controller=>"devise/groups", :id=>4, :locale=>nil}
My guess is the error stems from the controller being "devise/groups" as that's the only difference I spot. Is there a way I can tell it to not prepend "devise"? Or do I have to write new routes for all these bits? If I have to add new routes, how can I use resources in routes?
I suspect Devise will also break other links on other pages that I had to code this way.
routes:
Rails.application.routes.draw do
devise_for :admins
get 'search/index'
get 'tags/:tag', to: "search#index", as: :tag
scope "(:locale)", :locale => /#{I18n.available_locales.join("|")}/ do
get 'home/index'
root :to => "home#index"
resources :brands
resources :faqs
resources :categories
resources :subgroups
resources :groups
end
UPDATE: I tried changing the link to the following
<% #groups.each do |group| %>
<li id=<%= group.id %>><%= link_to(t("navbar." + group.name.singularize.downcase), url_for(:controller => 'groups', :action => 'show', :id => group.id)) %></li>
<% end %>
But it still comes up with "devise/groups" as the controller when I access the sign-in page. After I sign in, there's no problem.
I have a strange "fix" but it certainly does not feel correct in the slightest. I created new Controllers that derive from Devise::[name]Controllers, and did the following to whatever methods I needed
def new
super
end
Then edited routes.rb
devise_for :admins, :controllers => {:[name] => "[name]"}
with a new :[name] => "[name]" pair for each Controller I had to make.
determined which ones I needed by looking at rake routes. Everything's working, but I'm sure there's a cleaner fix than this out there.
p.s. you may need to run rails g devise:views

DRY routing for one polymorph resource with nested resources

Given the following models:
class Blog < ActiveRecord::Base
has_many :posts
end
class SiteBlog < Blog
end
class ProjectBlog < Blog
end
class Post <ActiveRecord::Base
belongs_to :blog
end
And the following routes:
resources :blogs do
resources :posts
end
In say a form partial, the following will work fine if #blog is a Blog:
form_for [#blog, #post] ...
However, if #blog is a ProjectBlog or SiteBlog, it bombs since it will be looking for a URL helper such as project_blog_posts.
I guess something like this would solve this:
[:project_blogs, :site_blogs].each |blogs| do
resources blogs do
resources :posts
end
end
I'm wondering whether there's a way to use the routes for subclassed models (e.g. ProjectBlog) to use the routes of the parent model (Blog). The "as" option only deals with the last object passed like [#blog, #post] to form_for.
Update
As requested below, here are the routes:
resources :blogs, only: [:show] do
resources :posts, only: [:new, :create, :edit, :update]
end
blog_posts POST /blogs/:blog_id/posts(.:format) posts#create
new_blog_post GET /blogs/:blog_id/posts/new(.:format) posts#new
edit_blog_post GET /blogs/:blog_id/posts/:id/edit(.:format) posts#edit
blog_post PUT /blogs/:blog_id/posts/:id(.:format) posts#update
blog GET /blogs/:id(.:format) blogs#show
Update 2:
The tip from an answer below:
form_for [#blog, #post], url: blog_posts_path(#blog, #post) do |f|
This works for "new" actions only, for "edit" actions, I'd get - as expected - a bad URL:
params[:action] # => "edit"
blog_posts_path(#blog, #post) # => "/blogs/publikationsreihe-tafelrunde/posts.5"
So the "if" I mentioned would fix this:
form_for [#blog, #post], url: params[:action]=='new' ? blog_posts_path(#blog, #post) : blog_post_path(#blog, #post) do |f|
But this looks incredibly clumsy, there must be a better way.
Easily solvable by passing the resource url to the form:
<%= form_for [#blog, #post], :url => blog_posts_path(#blog, #post) do |f| %>
...
<%- end %>

How do I get my app to go to this custom view?

I have this custom action in my videos controller:
def upvoted_songs
#votes = current_user.videos_votes.where("value = 1")
#videos = #votes.videos.page(params[:page]).per(15)
end
this is my routes:
resources :videos do
member do
put 'topic_update'
get 'upvoted_songs'
end
end
And this link in my videos index view:
<%= link_to "Upvoted Songs", videos_path, :action => "upvoted_songs", :class => "upvoted_songs chosen_home_option" %>
and a view file called videos/upvoted_songs.html.erb.
Why doesn't the link direct to the upvoted_songs.html.erb view but rather stay on the video index view?
UPDATE:
These is my routes.rb:
root :to => "videos#index"
resources :video_votes
resources :videos do
resources :comments
member do
put 'topic_update', :on => :member
get 'upvoted_songs', :on => :collection, :as => 'upvoted'
end
end
resources :comment_titles
resources :users
resources :profiles
resources :genres
resources :topics
resources :topicables
resource :session
I initially get this error:
ArgumentError
can't use member outside resource(s) scope
Then after refreshing the page, I get this error:
ActionController::RoutingError in Videos#index
Showing /rubyprograms/dreamstill/app/views/videos/_video.html.erb where line #22 raised:
No route matches {:action=>"show", :id=>#<Video id: 485, title: "I'm Ready For You", description: nil, embed_code: nil, thumbnail_url: nil, released: nil, user_id: 57, created_at: "2011-04-02 08:47:36", updated_at: "2011-04-09 22:42:48", video_url: "http://www.youtube.com/watch?v=wy86KNtOjVg", video_votes_count: 0, vote_sum: 3, rank_sum: 28927.724512>, :controller=>"videos"}
22: <%= link_to video.title, video_path(video), :class => "normal" %>
To see what routes are available for use in your app use rake routes on the command line in the root directory of the app. You should see a line that refers to upvoted_songs.
Then use it like so:
<%= link_to "Upvoted Songs", upvoted_songs_video_path(video), :class => "upvoted_songs chosen_home_option" %>
Since you have it has a member route the url helper will take a video object (or id) and generate a url that looks something like: /videos/7/upvoted_songs
However, your code suggests that you might be doing something that does not rely on a single video object, and wouldn't need that in the URL either. So you would want to change that route from a member route to a collection route. The URL would then end up looking something like /videos/upvoted_songs and you wouldn't be passing it a video object.
Hope this helps :)
PART 2
Remove the member block:
resources :videos do
resources :comments
put 'topic_update', :on => :member
get 'upvoted_songs', :on => :collection, :as => 'upvoted'
end
You are linking to videos_path, which is a helper for "videos#index".
As ctcherry explained, your current route is using a member route and not a collection. The following is more what you're looking for:
resources :videos do
put 'topic_update', :on => :member
get 'upvoted_songs', :on => :collection, :as => 'upvoted'
end
Then you can use upvoted_videos_path in place of just videos_path.
You don't have an id. Do a rake routes | grep upvoted and see what your route should look like.
it's probably something like upvoted_songs_video_path(video)

Resources