Rails "No route matches POST /images/1" error - ruby-on-rails

I looked through several other similar help questions, and I'm not seeing my error. I have destroy, new, create all working, but post and show throw errors. Also oddly enough, clicking the 'edit' button on the index view throws an error, but going directly to http://localhost:3000/images/1 gives me the 'show' page (no idea why it isn't giving an edit page).
relevant files:
images_controller.rb
class ImagesController < ApplicationController
def index
#images = Image.all
end
def new
#image = Image.new
end
def create
#image = Image.new(image_params)
if #image.save
redirect_to images_path, notice: "Your image #{#image.name} has been uploaded."
else
render "new"
end
end
def edit
#image = Image.find(params[:id])
end
def destroy
#image = Image.find(params[:id])
#image.destroy
redirect_to images_path, notice: "The image #{#image.name} has been removed from the database."
end
def show
#image = Image.find(params[:id])
end
private
def image_params
params.require(:image).permit(:name, :attachment)
end
end
routes.rb
Rails.application.routes.draw do
devise_for :admin_users, ActiveAdmin::Devise.config
ActiveAdmin.routes(self)
resources :images#, only: [:index, :new, :create, :update, :edit, :show, :destroy]
root "images#index"
end
Note: I have also added the lines
get 'images/edit'
get 'images/details'
But to no avail.
index.html.erb:
<% if !flash[:notice].blank? %>
<div class="alert alert-info">
<%= flash[:notice] %>
</div>
<% end %>
<br />
<%= link_to "New Image", new_image_path, class: "btn btn-primary" %>
<br />
<br />
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Name</th>
<th>View Link</th>
<th> </th>
</tr>
</thead>
<tbody>
<% #images.each do |image| %>
<tr>
<td><%= image.name %></td>
<td><%= link_to "#{image.name}", image.attachment_url %></td>
<td><%= button_to "Edit", image, method: :edit, class: "btn btn-primary", confirm: "edit #{image.name}?" %></td>
<td><%= button_to "Show", image, method: :show, class: "btn btn-primary"%></td>
<td><%= button_to "Delete", image, method: :delete, class: "btn btn-danger", confirm: "Are you sure that you wish to delete #{image.name}?" %></td>
</tr>
<% end %>
</tbody>
</table>

I suppose there are no HTTP methods like this:
method: :edit, method: :show
Try to do smth like this:
link_to "Edit", edit_image_path(image)
link_to "Show", image_path(image)
And remove this line from routes.rb
get 'images/edit'
resources has already created rout to edit action for you. You can see it http://localhost:3000/rails/info/routes

button_to by default will make post request you need link_to "edit" to make get request. when you type in your browser http://localhost:3000/images/1 you are making get request so it works.
link_to "Edit", edit_image_path image
check these links for link_to and button_to
http://apidock.com/rails/ActionView/Helpers/UrlHelper/link_to
http://apidock.com/rails/ActionView/Helpers/UrlHelper/button_to

Related

Rails, form is calling wrong action

I have made my form:
<tbody>
<% #player.bases.each do |basis| %>
<td><%= basis.id %></td>
<td><%= image_tag(basis.image_url(:thumb), class: 'thumbnail') %></td>
<td><%= link_to basis.name, basis %></td>
<td><%= basis.cost %></td>
<td><%= basis.short_info %></td>
<td>
<%= form_for #player, url: {:controller => 'players', :action => :remove_detail} do |f| %>
<%= f.hidden_field :type, :value => 'basis' %>
<%= f.hidden_field :detail_id, :value => basis.id %>
<%= f.submit 'Remove',class: 'btn btn-danger' %>
<% end %>
</td>
<% end %>
</tbody>
In my routes, I have added this:
resources :players do
collection do
get 'search'
post 'remove_detail'
end
end
I have remove_detail in my players_controller.rb, and I have added this action to before_action to get current player. However when I press on my Remove button, it throws me error and tries to run update action of my controller. Why?
My before_action:
before_action :set_player, only: [:show, :edit, :update, :destroy, :remove_detail]
My remove_detail:
def remove_detail
type = params['type']
id = params['detail_id']
if type == 'basis'
basis = Basis.find(id)
name = basis.name
#player.bases.delete(basis)
end
redirect_to #player, notice: "#{name} detail is removed"
end
To fix that, try as follows:
First of all, I'd redefine your routes as follows:
resources :players do
member do
delete 'remove_detail'
end
collection do
get 'search'
end
end
This will generate proper url for deleting a detail for a "single Player":
/players/:id/remove_detail
Because of REST-y nature of Rails, we defined the url to be accessible by performing delete request.
Your form change accordingly:
<%= form_for #player, { url: { action: "remove_detail" }, method: :delete } do |f| %>
Changing your routes to use delete method is more to keep the convention of Rails. Post would make your application work too, but - its just Rails-y way.
Good luck!

Rails - Updating records using Best in Place

I'm building a marketplace app where I'm trying to use the Best in Place gem to allow sellers to add a tracking number for each of their orders.
I get a NoMethodError which I'm not able to resolve.
NoMethodError in Orders#sales
undefined method `tracking' for nil:NilClass
The error points to the best in place line below in the view page. This view page is based on the method Sales (in the controller below) where I filter for orders for that particular seller.
Here is my routes.rb with order routing. Since orders need not be edited or destroyed, I didn't create an edit or delete route.
resources :listings do
resources :orders, only: [:new, :create, :update]
collection { post :import }
end
Here is a snippet from my orders controller
class OrdersController < ApplicationController
before_action :set_order, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
before_action :check_user, only: [:edit, :update]
def sales
#orders = Order.all.where(seller: current_user).order("created_at DESC")
end
def update
#order.update_attributes(params[:order])
end
def check_user
if current_user.id != #seller && current_user.name != "admin admin"
redirect_to root_url, alert: "Sorry, you are not the seller of this listing"
end
end
Here is my view page:
<table class="table table-striped table-bordered">
<tr>
<th class="col-md-2">Image</th>
<th class="col-md-2">Item</th>
<th class="col-md-1">Price</th>
<th class="col-md-2">Customer</th>
<th class="col-md-2">Date Sold</th>
<th class="col-md-2">Shipment Tracking #</th>
<th class="col-md-1">Carrier (UPS, USPS, etc.)</th>
</tr>
<% #orders.each do |order| %>
<tr>
<td><%= image_tag order.listing.image.url(:thumb) %></td>
<td><%= order.listing.name %></td>
<td><%= number_to_currency(order.listing.price) %></td>
<td><%= order.buyer.name %></td>
<td><%= order.created_at.strftime("%B %-d, %Y") %></td>
<td><%= best_in_place #order, :tracking, :type => :input %> </td>
<td><%= best_in_place #order, :carrier, :type => :input %></td>
</tr>
<% end %>
</table>
Been stuck on this for a while. Appreciate any help on this.
I think the problem is that you are calling #order inside your .each method.
Try:
<%= best in place order, :tracking, :type => :input %>
You will need to change the next line in your view as well.
I figured it out. The problem was that since I was using best_in_place in a non-Activerecord environment (as part of a table with a list of orders), I needed to pass the order id explicitly. I found this in the best_in_place documentation https://github.com/bernat/best_in_place#non-active-record-environments
I created a custom route for the update action
put 'orderupdate' => "orders#update"
Then in my do loop in the view, I used the custom path for the route above and passed the order id to that route.
<% #orders.each do |order| %>
<tr>
<td><%= order.id %></td>
<td><%= image_tag order.listing.image.url(:thumb) %></td>
<td><%= order.listing.name %></td>
<td><%= number_to_currency(order.listing.price) %></td>
<td><%= order.buyer.name %></td>
<td><%= order.created_at.strftime("%B %-d, %Y") %></td>
<td><%= best_in_place order, :tracking, :type => :input, :url => orderupdate_path(id: order.id) %> </td>
<td><%= best_in_place order, :carrier, :type => :input, :url => orderupdate_path(id: order.id) %> </td>
</tr>
<% end %>
Here is the update method in my controller:
def update
#order = Order.find(params[:id])
respond_to do |format|
if #order.update(order_params)
format.html { redirect_to sales_url, notice: 'Order updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
Hope this helps someone!

Rails 4: No route matches - issue with relationships missing id key

I am hoping someone can help me. I am getting the following issue:
No route matches {:action=>"show", :controller=>"stocks", :stockpile_id=>#<Stock id: 17, stockpile_id: 3, code: "rttrtrt", name: "", description: "", quantity: nil, cost_pence: nil, information: "", created_at: "2013-08-18 19:52:46", updated_at: "2013-08-18 19:52:46">, :id=>nil, :format=>nil} missing required keys: [:id]
When visiting the following URL: /admin/stockpiles/3/stocks/
My routes look like:
scope '/admin' do
root :to => 'admin#index', :as => 'admin'
resources :stockpiles,:companies
scope :path => 'stockpiles/:stockpile_id' do
resources :stocks
end
end
The data contained in the error message:
id | stockpile_id | code | name | description | quantity | cost_pence | information | created_at | updated_at
17 | 3 | rttrtrt | | | | | | 2013-08-18 19:52:46.856864 | 2013-08-18 19:52:46.856864
My Stock Model:
class Stock < ActiveRecord::Base
belongs_to :stockpile
end
Nothing interesting in the Stockpile model, just that it has many stocks..
Here is my controller:
class StocksController < ApplicationController
before_action :set_stock, only: [:show, :edit, :update, :destroy]
def index
#stockpile = Stockpile.find(params[:stockpile_id])
#stocks = #stockpile.stocks.all
end
def show
end
def new
#stockpile = Stockpile.find(params[:stockpile_id])
#stock = #stockpile.stocks.new
end
def edit
end
def create
#stockpile = Stockpile.find(params[:stockpile_id])
#stock = #stockpile.stocks.new(stock_params)
if #stock.save
redirect_to #stock, notice: 'Stock was successfully created.'
else
render action: 'new'
end
end
def update
if #stock.update(stock_params)
redirect_to #stock, notice: 'Stock was successfully updated.'
else
render action: 'edit'
end
end
def destroy
#stock.destroy
redirect_to stocks_url, notice: 'Stock was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_stock
#stockpile = Stockpile.find(params[:stockpile_id])
#stock = #stockpile.stocks.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def stock_params
params.require(:stock).permit(:code, :name, :description, :quantity, :cost_pence, :information)
end
end
And here is the view in question:
<div class="page-header">
<%= link_to new_stock_path(params[:stockpile_id]), :class => 'btn btn-primary' do %>
<i class="icon-plus icon-white"></i>
New Stock
<% end %>
<h1>Listing stocks</h1>
</div>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Stockpile</th>
<th>Code</th>
<th>Name</th>
<th>Description</th>
<th>Quantity</th>
<th>Cost pence</th>
<th>Information</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<% #stocks.each do |stock| %>
<tr>
<td><%= stock.stockpile %></td>
<td><%= stock.code %></td>
<td><%= stock.name %></td>
<td><%= stock.description %></td>
<td><%= stock.quantity %></td>
<td><%= stock.cost_pence %></td>
<td><%= stock.information %></td>
<td><%= link_to 'Show', stock %></td>
<td><%= link_to 'Edit', edit_stock_path(stock) %></td>
<td><%= link_to 'Destroy', stock, confirm: 'Are you sure?', method: :delete %></td>
</tr>
<% end %>
</tbody>
</table>
Help would be much appreciated - looks like something weird is going on because stockpile_id seems to be set to stock, and there seems to be no stock params or anything - so we get the missing id error.
Thanks.
It would appear that you need to pass in the stockpile as well as the stock..
<td><%= link_to 'Show', [#stockpile, stock] %></td>
Should do that.
As opposed to using the scope you can probably just use a nested resource in your routes
resources :stockpiles do
resources :stocks
end
and then you can DRY up your stock controller
class StocksController < ApplicationController
before_action :set_stockpile
.....
def set_stockpile
#stockpile = Stockpile.find params[:stockpile_id]
end

Rails links not connecting properly

I am a rails beginner and I have created 3 models/controllers/views using rails generate scaffold:
Subjects, which have many topics
Topics, which have many notes
Notes
When I go to http://localhost:3000/subjects/1/topics, Rails lists the empty list of topics and when the 'New Topic' link is clicked, you are taken to http://localhost:3000/topics/new.
Should and how do I get the link for 'New Topic' to take the user to http://localhost:3000/subjects/:id/topics/new instead of http://localhost:3000/topics/new and should the new topic form submit to http://localhost:3000/subjects/:id/topics/new instead of http://localhost:3000/topics?
views/topics/index:
<h1>Listing topics</h1>
<table>
<tr>
<th>Name</th>
<th></th>
<th></th>
<th></th>
</tr>
<% #topics.each do |topic| %>
<tr>
<td><%= topic.name %></td>
<td><%= link_to 'Show', topic %></td>
<td><%= link_to 'Edit', edit_topic_path(topic) %></td>
<td><%= link_to 'Destroy', topic, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New Topic', new_topic_path %>
controllers/topics:
def new
#topic = Topic.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #topic }
end
end
def edit
#topic = Topic.find(params[:id])
end
def create
#topic = Topic.new(params[:topic])
#topic.subject_id = params[:project_id]
respond_to do |format|
if #topic.save
format.html { redirect_to subject_path(#topic.subject_id), notice: 'Topic was successfully created.' }
format.json { render json: #topic, status: :created, location: #topic }
else
format.html { render action: "new" }
format.json { render json: #topic.errors, status: :unprocessable_entity }
end
end
end
new topics form:
<%= form_for(#topic) do |f| %>
<% if #topic.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#topic.errors.count, "error") %> prohibited this topic from being saved:</h2>
<ul>
<% #topic.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
routes:
resources :subjects do
resources :topics do
resources :notes
end
end
resources :notes
resources :topics
resources :subjects
root :to => 'subjects#index'
when you go to http://localhost:3000/subjects/1/topics the action index of controller TopicsController is called with the params[:subject_id] set to 1.
So in your controller action, you have to check for this parameter and filter the topics if it is given
def index
if params[:subject_id].present?
#subject=Subject.find params[:subject_id]
#topics=#subject.topics
else
#topics=Topic.all
end
end
and in your index view, you have to use this url, if #subject ist present:
<%= link_to 'New Topic', #subject.present? ? new_subject_topic_path(#subject) : new_topic_path %>
in your topics new action again you get the :subject_id as a parameter:
def new
#subject=Subject.find params[:subject_id]
#topic = #subject.topics.new
end
then in your topics form, you can forward the subject_id in a hidden field:
<%= form_for(#topic) do |f| %>
...
<%= f.hidden_field :subject_id %>
...
<% end %>
The rest of your TobicsController can stay the same. The Topic is assiciated to the Subject by the subject_id
Once you have declared the nested resources, don't declare those resources again.
Deep nesting of resources is not recommended. You should think about doing shallow nesting, and you can read about this in the Rails Routing Guide.
One way to avoid deep nesting (as recommended above) is to generate
the collection actions scoped under the parent, so as to get a sense
of the hierarchy, but to not nest the member actions. In other words,
to only build routes with the minimal amount of information to
uniquely identify the resource, like this:
resources :posts do
resources :comments, only: [:index, :new, :create]
end
resources :comments, only: [:show, :edit, :update, :destroy]
This idea strikes a balance between descriptive routes and deep
nesting.

How to delete nested record

My girl model has comments with using gem 'acts_as_commentable'
When I access example.com/girls/show/1
It shows ID#1 girl's profile.
All the posted comments are shown in the bottom of this page.
For each comment row, I want to add delete button to delete a comment.
If it should pass the parameter to girls_controller.rb's comment_destroy action.
How action part and view should be??
It keeps undefined local variable or method `girls' error with codes below.
"girls/show.html.erb" view should be something like this. Just a part.
<table>
<tr>
<th>ID</th>
<th>Title</th>
<th>Body</th>
<th>Subject</th>
<th>Delete</th>
</tr>
<% #all_comments.each do |comment| %>
<tr>
<td><%= comment.id %></td>
<td><%= comment.title %></td>
<td><%= comment.body %></td>
<td><%= comment.subject %></td>
<td><%= button_to 'comment_destroy', girls, confirm: 'Are you sure?', :disable_with => 'deleting...', method: :delete %></td>
</tr>
<% end %>
</table>
girls_controller.rb's comment_destroy action should be something like this
def comment_destroy
#comment = comment.find(params[:id])
#comment.destroy
respond_to do |format|
format.html { redirect_to girls_url }
format.json { head :ok }
end
redirect_to :controller => 'girls', :action => 'show', :id => params[:girls][:id]
flash[:notice] = "comment deleted!"
end
It looks like you have comments nested under a girl, and you want to delete the comment.
Routes
resources :girls do
resources :comments, only: [:create, :destroy]
end
Then, you have a comments controller that handles your creation and destroy.
<%= button_to 'comment_destroy', [#girl, comment], confirm: 'Are you sure?', :disable_with => 'deleting...', method: :delete %>
The destroy method in your comments controller:
def destroy
#girl = Girl.find(params[:girl_id])
#comment = #girl.comments.find(params[:id])
if #comment.destroy
redirect_to #girl, notice: "Comment Removed"
else
redirect_to #girl, error: "We could not remove the comment"
end
end
end
UPDATE -- based on user's request to use a non-restful solution
Routes:
resources :girls do
member do
delete :delete_comment, to: "girls#delete_comment", as: "delete_comment"
end
end
controller
def delete_comment
#girl = Girl.find(params[:id])
#comment = #girl.comments.find(params[:comment_id])
if #comment.destroy
redirect_to #girl, notice: "Comment Removed"
else
redirect_to #girl, error: "We could not remove the comment"
end
end
View link
<%= button_to 'comment_destroy', delete_comment_path(#girl, comment_id: comment.id), confirm: 'Are you sure?', :disable_with => 'deleting...', method: :delete %>
Final note: I really don't like this solution. You should have a Comments controller and go with my first solution.

Resources