I'm getting
ActionView::Template::Error (No route matches {:action=>"to_approve", :controller=>"microposts", :id=>nil} missing required keys: [:id]):
No route matches {:action=>"to_approve", :controller=>"microposts",
:id=>nil} missing required keys: [:id]
But it make no sense because I'm routing to different route
route.rb
match '/microposts/:id/approve', to: 'microposts#to_approve' , via: [:get, :post], as: 'approve_micropost'
match '/microposts/to_approve', to: 'microposts#approve' , via: :get
controller.rb
def show
#tag = Tag.find(params[:id])
#microposts = #tag.microposts
end
show.html.rb
<%= render #microposts %>
_micropost.html.rb - Here is the line it shows the error on
<% if is_an_admin? %>
<%= link_to "Approve", approve_micropost_path(micropost.id) %>
<% end %>
micropost_controller.rb
def approve
#microposts = Micropost.unapproved
end
def to_approve
micropost = Micropost.unapproved_by_id(params[:id])
if micropost.update_attributes(approved: true)
flash[:success] = "Approved!"
else
flash[:error] = "Not approved!"
end
redirect_back_or microposts_to_approve_path
end
micropost.rb
default_scope { where(approved: true).order('microposts.created_at DESC')}
def self.unapproved
self.unscoped.all.where(approved: false).order('microposts.created_at DESC')
end
def self.unapproved_by_id(id = nil)
self.unscoped.all.where(id: id)
end
You can see it tries to create microposts_to_approve_path with :id which obviously not exists, but I wrote approve_micropost_path.
What am I missing?
Plus, in route for microposts_to_approve_path I permitted [:get, :post] although I only want to allow access to to_approve method through on_click events (post?) and there is no view for it.. How should I rewrite this?
rake routes:
microposts POST /microposts(.:format) microposts#create
micropost DELETE /microposts/:id(.:format) microposts#destroy
approve_micropost GET|POST /microposts/:id/approve(.:format) microposts#to_approve
microposts_to_approve GET /microposts/to_approve(.:format) microposts#approve
On the error page, the parameters:
Request
Parameters:
{"id"=>"4",
"name"=>"tag name"}
Solution
The problem was because I use default_scope and than the object the I was working with wasn't OK.
Before fix
#microposts = #tag.microposts ##microposts is CollectionProxy
After
#microposts = #tag.microposts.all ##microposts is AssociationRelation
Once I've change to .all the problem was solved.
BTW, is it a bug? In my prespective default_scope shouldn't change the default behavior..
If you want it to only respond to a post, then try changing your link to use the method 'post'.
<% if is_an_admin? %>
<%= link_to "Approve", approve_micropost_path(micropost.id), method: :post %>
<% end %>
Conversely, if you want it to route to microposts#to_approve on a get, then make your link explicitly call get.
<% if is_an_admin? %>
<%= link_to "Approve", approve_micropost_path(micropost.id), method: :get %>
<% end %>
Then you should be routed to microposts#to_approve using POST. However, since you re allowing either action to take place, make sure in your to_approve action, you'll have to check for request type. Such as:
#microposts controller
def to_approve
if request.post?
# Do post related things
else
# Do get related things
end
end
Sidenote *** using the to_approve action on the approve url, and using the approve action on the to_approve url is confusing, things you might forget why-you-did-what-you-did when you look at the code 6 months from now.
Edit
An alternative might be to break apart the routes so you aren't calling an if statement in your controller.
route.rb
post '/microposts/:id/approve', to: 'microposts#approve', as: 'approve_micropost'
get '/microposts/:id/to_approval', to: 'microposts#to_approve', as: 'micropost_approvals'
resources :microposts
Related
I am developing a project in Ruby on rails 5.2, and in this route it tells me that I have an error and that the specified route is not found. but when checking, the route is there or at least I think so.
Here's my routes.rb:
resources :checkin do
post :get_barcode, on: :collection
end
checkin_controller.rb:
class CheckinController < ApplicationController
def index
#checkin = CheckIn.all
end
def show
end
def new
#checkin = CheckIn.new
#checkin.upc = params[:upc]
end
def edit
end
def update
end
def destroy
end
def get_barcode
#checkin = Merchant.find_or_initialize_by(upc: params[:upc])
unless #checkin.new_record?
redirect_to #checkin
else
redirect_to new_product_path(upc: params[:upc])
end
end
end
And my link in my view:
<%= link_to "Check-In", checkin_path, :class => "nav-link" %>
here's a image of my error page:
If you run rake routes in your console, you'll see that your routes are:
get_barcode_checkin_index POST /checkin/get_barcode(.:format) checkin#get_barcode
checkin_index GET /checkin(.:format) checkin#index
POST /checkin(.:format) checkin#create
new_checkin GET /checkin/new(.:format) checkin#new
edit_checkin GET /checkin/:id/edit(.:format) checkin#edit
checkin GET /checkin/:id(.:format) checkin#show
PATCH /checkin/:id(.:format) checkin#update
PUT /checkin/:id(.:format) checkin#update
DELETE /checkin/:id(.:format) checkin#destroy
As you can see, the checkin_path expects an id, which you are not providing here:
<%= link_to "Check-In", checkin_path, :class => "nav-link" %>
Your error probably says something about missing id, but you don't provide the error in your question, so we can't see exactly what it says.
BTW, by convention, CheckinController should probably be CheckinsController. And your routes should probably be:
resources :checkins do
post :get_barcode, on: :collection
end
As you said in one of your comments, you're expecting the URL for the index page?
Then instead of
<%= link_to "Check-In", checkin_path, :class => "nav-link" %>`
you need to use
<%= link_to "Check-In", checkin_index_path, :class => "nav-link" %>
I am working with rails I have a controller name books and has a user defined method in it .I need to call this method so that i can see the output on console.And I dont want to call this method in helpers.
def approve
#user=current_user.users.find params[:id]
puts '#{#usery}'
end
Also I Have a link
<%= link_to 'approve',users_path,data: { :confirm => 'Are you sure to delete the folder and all of its contents?'} %>
.When i click on this link I want to call the above method on it .
You'll just need to define a route and call it through that:
#config/routes.rb
resources :users do
get :approve, on: :member
end
<%= link_to "Approve", users_approve_path(#user) %>
As #Rich suggested that, you can achieve it by member. Please note that when you'll create a member route in member block
resources :users do
member do
get 'approve'
end
end
then you'll get the params[:id]. Like
def approve
#user = User.find params[:id]
puts '#{#user}'
end
and when create a member route using :on then you'll get params[:user_id]. Like
def approve
#user = User.find params[:user_id]
puts '#{#user}'
end
Path will be same in both cases that is
<%= link_to "Approve", users_approve_path(#user) %>
Source Rails - Adding More RESTful Actions
Happy coding !!!
So I have a simple list of messages that users can submit. I'm trying to put a delete button (that works) for each message. But as you can see here you get an error about an entirely different action if you click the button. I'm not totally sure about where I went wrong. My guess is that I'm out of my depth in the controller area. Here are all the applicable files.
Routes.rb:
Rails.application.routes.draw do
root 'messages#index', as: :home
get '/new' => 'messages#new', as: :edit
resources :messages
post '/new' => 'messages#create', as: :create
delete 'messages/:id' => 'messages#destroy', as: :delete
The relevant controller:
class MessagesController < ApplicationController
def index
#messages=Message.all
end
def new
#messages=Message.new
end
def destroy
#messages=Message.find(params[:id])
#messages.destroy
end
def create
#messages = Message.new(message_params)
if #messages.save
redirect_to '/'
else
render 'new'
end
end
private
def message_params
params.require(:message).permit(:content, :subject)
end
end
The Relevant View:
<div class="main">
<div="messages">
<%#messages.each do |t|%>
<h2 class="subject"><%=t.subject%></h2>
<p class="content"><%=t.content%></p>
<%=link_to "Delete Message", delete_path(t)%>
<% end %>
<%=link_to "Create Message", edit_path%>
</div>
</div>
You need to pass the method DELETE as well, otherwise it will perform the simply GET request. Here's how:
<%=link_to "Delete Message", delete_path(t), :method => 'delete' %>
Remember if you do not mention any method in link_to, the default will be taken as GET. So you have to be explicit about other HTTP methods.
Edit:
Either use resources :messages, or use the routes that you wrote yourself. Using resources :messages is a bit easier, and it is the preferred way.
Using resources :messages, you'd have to write:
<%= link_to "Delete Message", t, :method => 'delete' %>
Edit 2:
You are getting the error Template is missing, because in your destroy method, neither you are rendering anything, nor you are redirect_toing anything. After you destroy the object, you will have to tell where should it go. Like if you want the user to go all messages page after he/she destroys the record, you need to add the following line to the end of the method:
redirect_to messages_path
I have a Rails app that is supposed to send a POST request, but for some reason is sending a GET.
View:
<% if #competition.users.exclude?(#user) %>
<%= link_to 'Attend Competition', attend_competition_path(#competition.id), :method => :post %>
<% else %>
<%= link_to 'Withdraw', withdraw_competition_path(#competition.id), :method => :post %>
<% end %>
Controller:
def attend
p current_user.daily
#competition = Competition.find(params[:id])
if #competition.users.include?(current_user)
flash[:error] = "You're already attending this competition."
elsif current_user.daily == []
flash[:error] = "You must have a working device to compete."
else
current_user.competitions << #competition
flash[:success] = "Attending competition!"
end
redirect_to #competition
end
def withdraw
p "WITHDRAWING"
#competition = Competition.find(params[:id])
p #competition
attendee = Attendee.find_by_user_id_and_competition_id(current_user.id, #competition.id)
if attendee.blank?
flash[:error] = "No current attendees"
else
attendee.delete
flash[:success] = 'You are no longer attending this competition.'
end
p attendee
redirect_to #competition
end
Routes:
resources :competitions do
post 'attend', on: :member
end
resources :competitions do
member do
post 'withdraw'
end
end
So I click on the button and go to the page, but get an error that there is no route for a GET request. There shouldn't be a route for get requests, but it should be sending a post.
ActionController::RoutingError (No route matches [GET] "/competitions/1/withdraw")
One thing you can do is to run:
rake routes
That will show you all your available routes and their methods. I believe since you are doing a post to a method other then create that it is not understanding what you are trying to do. I am looking to see if I can find the proper way to do this, but I did find that the Rails documentation says:
If you are relying on the POST behavior, you should check for it in your controller's action by using the request object's methods for post?, delete?, :patch, or put?.
So you may need to check for a post in your controller action. I looked for an example of how to do this but couldn't find anything.
Looking at your routes, it should work the way you have it. One other thing to try is to use "put" instead of "post."
One other option that you may want to consider is to make it a form and style the button like a link if that is the look you are going for.
Mike Riley
I've an issue with the paths in the views and I don't know how to solve it.
I've "categories" that has_many "posts" and "posts" that belongs_to "categories".
1.- I want to show on home page the truncate last post of an specific category (the ID number "1"). Then I want that post to link to the show post path but I get this error:
"Unknow Action
The action 'index' could not be found for PostsController"
I think I've my paths wrong because I don't need the index view because I'm only going to show that specific post. So, I think that category_posts_path(#last_post) is not the right path (I don't know where to look for more info about making the route path in the views...). Actually, the browser is showing me that is looking for the "2" category when it is a post of the "1" category...? What am I doing wrong?
This is the browser route:
http://localhost:3000/en/categories/2/posts
This is my views/categories/home.html.erb file:
<div class="post_details">
<h2><%= #last_post.title %></h2>
<%= image_tag #last_post.image(:header), class: "post_image" %>
<p><%= truncate #last_post.body, length: 100 %></p>
<p class="button"><%= link_to "READ MORE", category_posts_path(#last_post) %></p>
</div>
2.- I have another path problem in the views/categories/show.html.erb file. I have a loop to show all the post of one specific category, but when I link in some post (to show it) there is the "index" error again:
"Unknow action
The action 'index' could not be found for PostsController"
This is the browser route:
http://localhost:3000/en/categories/1/posts
This is the views/categories/show.html.erb file:
<div class="post_details">
<h2><%= link_to post.title, category_posts_path(post) %></h2>
<%= image_tag post.image(:header), class: "post_image" %>
<p><%= post.body %></p>
</div>
This is the categories_controller.rb file:
class CategoriesController < ApplicationController
before_action :get_categories
def index
end
def show
#category = Category.find(params[:id])
end
def home
if params[:set_locale]
redirect_to root_url(locale: params[:set_locale])
else
#category = Category.find_by_id(1)
#last_post = #category.posts.order("created_at desc").first
end
end
def get_categories
#categories = Category.all.order("rank asc, name asc")
end
end
This is my posts_controller.rb file:
class PostsController < ApplicationController
def show
#category = Category.find(params[:category_id])
#post = #category.posts.find(params[:id])
end
end
This is my route.rb file:
scope '(:locale)' do
resources :categories do
resources :posts
end
resources :contacts
root 'categories#home'
get "/contact" => "contacts#new"
# static pages
get "/investment" => "contents#investment"
get "/partner-with-us" => "contents#partner", as: "partner"
get "/our-companies" => "contents#companies", as: "companies"
get "/site-map" => "contents#sitemap", as: "sitemap"
get "/terms-and-conditions" => "contents#terms", as: "terms"
get "/privacy" => "contents#privacy"
end
When you are nesting routes you should always consider what is the parent and whats a child in given route. Since your paths don't know anything about your associations you have to explicitly define every object in the nesting.
I.e. since you nested posts in categories linking to last post in given category would look like this:
category_post_path(#category, #last_post)
(I think you have also a typo there - category_posts_paths - which links to posts index index - hence the error. Use category_post_path. instead, and give it both parent category and the post.
You can run rake routes to see exact information on paths (or go to http://localhost:3000/rails/info/routes )