Rails: No route matches [POST] "/specials/1" - ruby-on-rails

This is the error I'm getting:
No route matches [POST] "/specials/1"
I understand that it's not able to produce the post route, or it isn't available.
Here's my view/form code:
<%= form_for(:special, :url => {:action => 'update', :id => #special.id}) do |f| %>
<table class="table table-responsive table-striped table-condensed table-hover" summary="Special form fields">
<tr>
<th>Order</th>
<td><%= f.text_field :order, class: "form-control" %></td>
</tr>
<tr>
<th>Name</th>
<td><%= f.text_field :name, class: "form-control" %></td>
</tr>
<tr>
<th>Description</th>
<td><%= f.text_field :description, class: "form-control" %></td>
</tr>
<tr>
<th>Fine Print</th>
<td><%= f.text_field :fine_print, class: "form-control" %></td>
</tr>
<tr>
<th>Active</th>
<td><%= f.text_field :active, class: "form-control" %></td>
</tr>
</table>
<div class="form-buttons">
<%= submit_tag("Update Special") %>
</div>
<% end %>
Heres's my controller code:
class SpecialsController < ApplicationController
def index
#specials = Special.sorted
end
def show
#special = Special.find(params[:id])
end
def new
#special = Special.new
end
def create
#Instantiation of object using form parameters
#special = Special.new(special_params)
#Save the object
if #special.save
#If success, redirect to index action
redirect_to(:action => 'index')
else
# Redisplay the form so user can fix problems
render('new')
end
end
def edit
#special = Special.find(params[:id])
end
def update
#Find an existing object using form parameters
#special = Special.find(params[:id])
#Update the object
if #special.update_attributes(special_params)
#If succeeds, redirect to index action
redirect_to(:action => 'show', :id => #special.id)
else
# If update fails, redisplay the form so user can fix problems
render('edit')
end
end
def delete
end
private
def special_params
params.require(:special).permit(:name, :description, :fine_print, :active, :order)
end
end
I noticed that there is an update path:
PATCH /specials/:id(.:format) specials#update
I can't figure out why the post route isn't being applied. It's looking for the right #special instance, but it doesn't seem to have the route available. Any advice?

Usually when updating a record, we do a patch request to the route. Your form should look like this:
<%= form_for(#special) do |f| %>
Rails will determine the correct route is PATCH /specials/:id based on the fact that #special has been persisted to the database.
If you decide to use this same form as a partial in your new view, just make sure to add this to your controller:
def new
#special = Special.new
end
That way whether you are on the new route or the edit route, there will always be a #special object for form_for to infer whether to POST to /specials or PATCH /specials/:id

Related

Undefined method for object defined in controller Rails

I have a view with a form and a table that displays some data from the database. Whenever I try to access the object from my controller in my view I get undefined method domain for "https://www.lookagain.co.uk/":String. But if do <%#savedHTML = ScrapedPage.all%> everything works fine. I know the I should not do that in the view as it defeats to purpose of MVC but I don't seem to fin a fix.
View:
<%= stylesheet_link_tag "masterstyles.css" %>
<% #url = 'default' %>
<%= form_for #url, :url => {:controller => "page_scraper", :action => "scrape"} do |f| %>
<%= f.text_field (:url) %>
<%= f.submit "Scrape" %>
<% end %>
<%#domain ='default'%>
<%#date ='default'%>
<%= form_for #domain, :url => {:controller => "page_scraper", :action => "compare"} do |f| %>
<%=select_tag 'domain', options_for_select(#savedHTML.collect{ |u| [u.domain, u.domain] })%>
<%=select_tag 'date', options_for_select(#savedHTML.collect{ |u| [u.created_at, u.created_at] })%>
<%= f.submit "compare" %>
<% end %>
<div class="subjects index">
<h2>FGH Page Scraper</h2>
<table class="listing" summary="Links list">
<tr class="header">
<th>ID</th>
<th>link</th>
<th>Created at</th>
<th>Updated at</th>
</tr>
<% #savedHTML.each do |page| %>
<tr>
<td><%= page.id %></td>
<td><%= page.domain %></td>
<td class="center"><%= page.created_at %></td>
<td class="center"><%= page.updated_at %></td>
<td class="actions">
<%= link_to("Delete", {:controller => 'page_scraper', :action => 'delete', :id => page.id}, :class => 'action delete') %>
</td>
</tr>
<% end %>
</table>
</div>
Controller:
class PageScraperController < ApplicationController
require 'nokogiri'
require 'open-uri'
require 'diffy'
require 'htmlentities'
def scrape
#url = watched_link_params[:url].to_s
puts "LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOG#{#url}"
#page = Nokogiri::HTML(open(#url))
coder = HTMLEntities.new
#encodedHTML = coder.encode(#page)
create
end
def index
#savedHTML = ScrapedPage.distinct.pluck(:domain)
end
def show
#savedHTML = ScrapedPage.distinct.pluck(:domain)
end
def new
#savedHTML = ScrapedPage.new
end
def create
#savedHTML = ScrapedPage.create(domain: #url, html: #encodedHTML, css: '', javascript: '')
if #savedHTML.save
puts "ADDED TO THE DATABASE"
redirect_to(root_path)
else
puts "FAILED TO ADD TO THE DATABASE"
end
end
def edit
end
def upadate
end
def delete
#savedHTML = ScrapedPage.find(params[:id])
end
def destroy
#savedHTML = ScrapedPage.find(params[:id])
#savedHTML.destroy
redirect_to(root_path)
end
def compare
#domain = params[:domain].to_s
puts #domain
redirect_to(root_path)
#timestamp
end
def watched_link_params
params.require(:default).permit(:url)
end
def compare_params
params.require(:domain).permit(:domain)
end
end
The problem is that in your controller you are saving only string-values to #savedHTML variable (pluck will give you only an array of attributes from given objects). Therefore you cant ask "some_string".domain because String class doesn't have a domain method.
If you have a domain method on ScrapedPage object then in your controller action (index or show - whatever you are dealing with) you should replace
#savedHTML = ScrapedPage.distinct.pluck(:domain)
with
#savedHTML = ScrapedPage.select(:domain).distinct
The latter will give you unique ScrapedPage objects based on domain value. Look here for further info and examples.
NB! also a tip for refactoring:
Use strong parameters under private section. Also, if you have the same query in your controller twice in different actions then it is better to make it in before_action like this:
class PageScraperController < ApplicationController
before_action :set_saved_html, only: %i[index show]
def index
end
def show
end
private
def watched_link_params
params.require(:default).permit(:url)
end
def compare_params
params.require(:domain).permit(:domain)
end
def set_saved_html
#savedHTML = ScrapedPage.select(:domain).distinct
end
end

undefined method `Ques_id' for #<Questionnaires:0x007fcc490c88f8>

In my application Questionnaires its my controller in that one datatype is t.integer "Ques_id" its not able to acess in my index page.when i run the index page then i will get NoMethodError in Questionnaires#index error. How to solve this error?
table
class CreateQuestionnaires< ActiveRecord::Migration
def up
create_table :questionnaires do |t|
#t.column "id", :string, :limit => 25
t.integer "Ques_id"
t.string "Qname"
t.string "Header"
t.string "Description"
t.string "username"
end
end
def down
drop_table :questionnaires
end
end
controller
class QuestionnairesController < ApplicationController
# layout false
layout "admin"
def index
#questionnaires = Questionnaires.sorted()
end
def view
#questionnaires= Questionnaires.find(params[:id])
end
def new
#questionnaires= Questionnaires.new()
end
def create
# Instantiate a new object using form parameters
#questionnaires = Questionnaires.new(questionnaires_params)
# Save the object
if #questionnaires.save
# If save succeeds, redirect to the index action
flash[:notice] = "questions saved successfully."
redirect_to(:action => 'index')
else
# If save fails, redisplay the form so user can fix problems
render('new')
end
end
def edit
#questionnaires = Questionnaires.find(params[:id])
end
def update
# Find an existing object using form parameters
#questionnaires= Questionnaires.find(params[:id])
# Update the object
if #Questionnaires.update_attributes(questionnaires_params)
# If update succeeds, redirect to the index action
flash[:notice] = "questions updated successfully."
redirect_to(:action => 'view', :id => #questionnaires.id)
else
# If update fails, redisplay the form so user can fix problems
render('edit')
end
end
def delete
#Questionnaires= Questionnaires.find(params[:id])
end
def destroy
questionnaires = Questionnaires.find(params[:id]).destroy
flash[:notice] = "questions '#{Questionnaires.name}' destroyed successfully."
redirect_to(:action => 'index')
end
private
def questionnaires_params
# same as using "params[:subject]", except that it:
# - raises an error if :subject is not present
# - allows listed attributes to be mass-assigned
params.require(:questionnaires).permit(:Ques_id,:Qname, :Header, :Description, :visible)
end
end
index page here i got error
<% #page_title = "Questionnaires" %>
<div class="Questionnaires index"
<h2>Questionnaires </h2>
<%= link_to("Add New questions", {:action => 'new'}, :class => 'action new') %><br>
<div><%= pluralize(#questionnaires.size, 'questionnaires') %> found</div>
<th>Questionnaires</th>
<table class="listing" summary="Questionnaires list">
<tr class="Header">
<th>Ques_id</th>
<th>Qname</th>
<th>Header</th>
<th>Description</th>
<th>Actions</th>
</tr>
<% #questionnaires.each do |objQuestionaire| %>
<tr class="<%= cycle('odd', 'even') %>">
<td><%= objQuestionaire.Ques_id %></td>
<td><%= objQuestionaire.Qname %></td>
<td><%= objQuestionaire.Header %></td>
<td><%= objQuestionaire.Description %></td>
<!--td><%= objQuestionaire.username %></td-->
<td class="actions">
<%= link_to("view", {:action => 'view', :id => objQuestionaire.id}, :class => 'action view') %>
<!-- <%= link_to("view", '#', :class => 'action view') %>-->
<!-- <%= link_to("Edit", '#', :class => 'action edit') %>-->
<%= link_to("edit", {:action => 'view', :id => objQuestionaire.id}, :class => 'action edit') %>
</td>
<%end %>
##its my error page
Showing /home/cabox/workspace/app_1/app/views/questionnaires/index.html.erb where line #20 raised:
undefined method `Ques_id' for #<Questionnaires:0x007fcc490c88f8>
Extracted source (around line #20):
17
18
19
20
21
22
23
<% #questionnaires.each do |objQuestionaire| %>
<tr class="<%= cycle('odd', 'even') %>">
<td><%= objQuestionaire.Ques_id %></td>
<td><%= objQuestionaire.Qname %></td>
<td><%= objQuestionaire.Header %></td>
<td><%= objQuestionaire.Description %></td>
Rails.root: /home/cabox/workspace/app_1
Application Trace | Framework Trace | Full Trace
app/views/questionnaires/index.html.erb:20:in `block in _app_views_questionnaires_index_html_erb__3549852765576469128_70257686505360'
app/views/questionnaires/index.html.erb:17:in `_app_views_questionnaires_index_html_erb__3549852765576469128_70257686505360'
It is looking for a Ques_id column in your table(Questionnaires) which is not been migrated yet. So only it throws
`NoMethodError`
Please update your database by doing
rake db:migrate
which will migrate all the required fields defined in the migration file to your database so that it will not throw error.

pass array hidden field in nested model rails

I have following code in my view:
<% #m1.map(&:id).each do |id|%>
<%= b.fields_for :modul1hours do |f| %>
<%= f.hidden_field :modul1_id, id %>
<%= f.text_field :module_est_hours, :size => 30 %>
</tr>
<% end %>
<%end%>
params passing in console
Parameters: {"authenticity_token"=>"LJ/ZME2lHZ7VwCDgPKX6OFe326fXSXo5UB4M0cPwbCE=", "esthour"=>{"rfp_id"=>"6", "ecommerce_est_hours"=>"", "modul1hours"=>{"module_est_hours"=>"3"}, "designpages_est_hours"=>"", "cms_est_hours"=>""}, "modul1_ids"=>["12", "13", "14"], "utf8"=>"✓", "project_id"=>"second", "commit"=>"Add Todo"}
Current user: admin (id=1)
modul1_ids is the hidden array based on that three text box is created but when i submit the page gives me:
ActionView::Template::Error (undefined method `merge' for 12:Fixnum):
in first textbox i passed 1
second 2
and in third 3
last value(3) isthe s passing that one can see in the console params module_est_hours"=>"3, but what about rest two fields y not passing and whats the solution for an error. Please help me.
Edit 1
<% #m1.map(&:id).each do |id|%>
<%= b.fields_for :modul1hours do |f| %>
<%= hidden_field_tag "modul1_ids[]", id %>
<%= f.text_field :module_est_hours, :size => 30 %>
</tr>
<% end %>
<%end%>
this code does not give the error, but also value is not stored in modul1hours table
The field of the modul1hours table are:
integer :modul1_id
decimal :module_est_hours
decimal :module_act_hours
integer :esthours_id
]
.rb
belongs_to :esthour
attr_accessible :module_est_hours,:module_act_hours
and controller
Update
def new
#esthour = Esthour.new
#gg = #esthour.modul1hours.build
#project = params[:project_id]
#rfp = params[:rfp_id]
#m1 = Modul1.where(:rfp_id => #rfp.id)
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #esthour }
end
end
over Update
# GET /project_todos/1/edit
def edit
#esthour = Esthour.find(params[:id])
end
def create
#project = params[:project_id]
#esthour = Esthour.new(params[:esthour])
user_params = params.select{|k,v| k.include?('esthour')}
respond_to do |format|
if #esthour.save
get_issue_attribute_param1(user_params)
format.html { redirect_to project_rfp_url(#project,#esthour.rfp_id), :notice => 'hours was successfully created.' }
format.json { render :json => #esthour, :status => :created, :location => #esthour }
else
format.html { render :action => "new" }
format.json { render :json => #esthour.errors, :status => :unprocessable_entity }
end
end
end
is there any build needed?eg Esthour.modul1hour.build in new def of controller coz record not saved in table?
view
<%= form_for #esthour,:rfp_id => #rfp.id,:project_id => #project do |b| %>
<%= b.hidden_field :rfp_id, :value => #rfp.id %>
<%= hidden_field_tag :project_id, #project %>
<table>
<tr> <td><b>Menutype </b></td>
<% if #rfp.menutype.present? %>
<td><%= #rfp.menutype %></td>
<td><%= b.number_field :menutype_est_hours %></td>
<% end %>
</tr>
<tr> <td> <b>Number of menu</b> </td>
<% if #rfp.numberofmenu.present? %>
<td><%= #rfp.numberofmenu %></td>
<td><%= b.number_field :numberofmenu_est_hours %></td>
<% end %>
</tr>
<tr>
<% #m1.map(&:id).each do |id|%>
<%= b.fields_for :modul1hours do |f| %>
<%= f.hidden_field :modul1_id, value => id %>
<%= f.text_field :module_est_hours, :size => 30 %>
</tr>
<% end %>
<% end %>
</table>
<%= b.submit 'Add Todo' %>
<% end %>
#esthour = Esthour.new
#gg = #esthour.modul1hours.build
#project = params[:project_id]
In this line:
<%= f.hidden_field :modul1_id, id %>
You are saying that you want the hidden field binded with modul1hour modul1_id method and options being id. Second parameter for FormBuilder hidden_field is expected to be a hash (which is then merged against default options). To do what you want do:
<%= f.hidden_field :modul1_id, value: id %>
Hidden fields aren't really the issue here
Apart from #BroiStatse's answer, I can see the issue as how you handle the params on your controller
Nested Models
Sending data to a controller sends that data to the relevant models. This is normally handled with accepts_nested_attributes_for, but can be handled manually too
From your controller code, I can't see how you're dealing with your extra data, but your error is caused by the incorrect merge of the params
Instead of saving the data manually, I would use the accepts_nested_attributes_for to save the data, like this:
#app/models/project.rb
Class Project < ActiveRecord::Base
accepts_nested_attributes_for :modul1hours
end
This will pass the params to your modul1hours model, where you'll then have to capture them with the relevant attr_accessible actions
f.fields_for
In order to get accepts_nested_attributes_for working properly, you have to ensure you use the f.fields_for function correctly.
You have to first build the ActiveRecord objects in your new controller action, like this:
def new
#project = Project.new
#project.modul1hours.build
end
Your problem is that you're then cycling through the ID's of your modul1hours model, yielding the f.fields_for artificially. Rails will only output an f.fields_for if the ActiveRecord object has been built in the controller:
"30" %>
This RailsCast gives you a better idea about this
What I would do is this:
#app/controllers/projects_controller.rb
def new
#project = Project.new
#m1.map(&:id).each do |i|
#project.modul1hours.build
end
end
#app/views/projects/new.html.erb
<%= b.fields_for :modul1hours do |f| %>
<%= hidden_field_tag :id, value :id %>
<%= f.text_field :module_est_hours, :size => "30" %>
<% end %>
I'm still thinking about how I would assign the ID's to the hidden field
Update
Try this:
#app/controllers/projects_controller.rb
def new
#project = Project.new
#project.modul1hours.build
end
Replace modul1hours with whatever your projects has_many of

form_for not submit all fields

Use a hidden field will fix my issue... i got it..
Hi All,
I am new to rails, trying to do some practice.
The app i am writing is trying to create a new "Post" See the view and controller below.
But it doesn`t work as what i expected...
the parameters pass to function "save", there is no "post_at" field...
How can i fix it???
Thanks
INFO: Parameters: {"authenticity_token"=>"Xc9VuvRL6GsUTaKyyNQxp8ovylEYwOMC+7hMcqdKizg=", "post"=>{"title"=>"First post", "content"=>"Write something"}, "commit"=>"save"}
View new_post.erb
<div class="post">
<% form_for #new_post, :url => { :action => "save" } do |f| %>
<p><%= f.error_messages %></p>
<br/>
<table>
<tr>
<td>Title</td>
<td><%= f.text_field :title %></td>
</tr>
<tr>
<td>Post at</td>
<td><%= #new_post.post_at %></td>
</tr>
<tr>
<td>Message</td>
<td><%= f.text_area :content, :cols => 100, :rows => 10 %></td>
</tr>
</table>
<br/>
<%= f.submit 'save'%>
<% end %>
</div>
Post Controler
class PostController < ApplicationController
def index
#all_posts = Post.find(:all)
render :action => "post"
end
def new
#new_post = Post.new
#new_post.post_at = Time.now
render :action => "new_post"
end
def save
#new_post = params[:post]
Post.create(#new_post)
redirect_to "/post"
end
end
Data Model:
class Post
include DataMapper::Resource
storage_names[:default] = "Post"
property :id, Serial
timestamps :at
property :title, String, :required => true, :length => 500
property :content, Text, :required => true, :lazy => false
property :post_at, DateTime
end
First off, your development will be a lot easier if you follow the REST principles.
Your controller should instead of save implement the create and update methods.
def index
#posts = Post.all
end
def new
#post = Post.new
end
def create
#post = Post.create(params[:post])
redirect_to #post
end
def show
#post = Post.get(params[:id])
end
def edit
#post = Post.get(params[:id])
end
def update
#post = Post.get(params[:id])
#post.update_attributes(params[:post])
redirect_to #post
end
def destroy
#post = Post.get(params[:id])
#post.destroy
redirect_to posts_path
end
This is a complete REST controller which has the views index.html.erb, new.html.erb, edit.html.erb, show.html.erb all in app/views/posts.
Sidenote: If you're new to Rails, it might be a good idea to learn how to use it with ActiveRecord before trying on DataMapper. That way you can use rails generate scaffold to get a full example of a way to do all this.
Your post_at value isn't a field, it's just displayed in the table. You want to do this:
<tr>
<td>Post at</td>
<td><%= f.datetime_select :post_at %></td>
</tr>
But in fact, there's more wrong with this code than that. For starters, Rails already has a field for this which will be set automatically called created_at. Next, your save action in your controller should be a create action to follow the Rails conventions.
I really think you should read the Getting Started guide which covers these basic fundamentals and then a book or two about Rails in more depth. These really teach you a lot.
Ryan is right about the cause of the problem.
If you need a readonly field then you could add a hidden field to make sure that the value is posted back:
<td><%= #new_post.post_at %><%= f.hidden_field :post_at %></td>
or you could replace it altogether with a readonly text_field:
<td><%= f.text_field :post_at, :readonly => true %></td>

Simple quantity function problems, shopping cart

I just picked up Agile Web Development with Rails 3rd Ed., and I'm going thru the Depot Application chapters, I'm attempting to create a simple Edit quantity function, and delete function. I've had luck with the delete function but no luck with the edit quantity function.
I'm going to provide a lot of information, so please don't feel overwhelmed. I've found this to be a challenging problem.
To add_to_cart.html.erb
<div class="cart-title">Your cart</div>
<table>
<% for item in #cart.items %>
<tr>
<td><% form_for #cart.items, :url => {:action => "cart_update", :id => "#{item.getinventoryid}"} do |f| %>
<%= f.text_field :quantity, :size => '3' %>
<%= f.hidden_field :id, :value => "#{item.getinventoryid}" %>
<%= f.submit 'cart_update' %>
<% end %></td>
<td><%=h item.quantity %> ×</td>
<td><%=h item.title %></li></td>
<td><%=h item.description %></td>
<td class="item-price"><%= number_to_currency(item.price) %></td>
<td><%= link_to 'remove', {:controller => 'inventories', :action => 'remove_cart_item', :id => "#{item.getinventoryid}"} %></td>
</tr>
<% end %>
<tr class="total-line">
<td colspan="4">Total</td>
<td class="total-cell"><%= number_to_currency(#cart.total_price) %></td>
</tr>
</table>
<%= button_to "Checkout", :action => 'checkout' %>
<%= button_to 'Empty cart', :action => 'empty_cart' %>
inventories_controller:
def cart_update
#inventory = Inventory.find(params[:id])
#cart = find_cart
#cart.increment_inventory_quantity(params[:inventory])
end
def remove_cart_item
inventory = Inventory.find(params[:id])
#cart = find_cart
#cart.remove_inventory(inventory)
redirect_to_index("The item was removed")
end
Cart.rb model
attr_accessor :items
def increment_inventory_quantity(id, quantity)
inventory_to_increment = #items.select{|item| item.inventory == inventory}
# We do this because select will return an array
unless product_to_increment.empty?
inventory_to_increment = inventory_to_increment.first
else
# error handling here
end
inventory_to_increment.quantity = quantity
end
def remove_inventory(inventory)
#items.delete_if {|item| item.inventory == inventory }
end
cart_item.rb model
attr_accessor :inventory, :quantity
def getinventoryid
#inventory.id
end
This produces strange results:
Notice the quantity 16 appears in both items from my loop (#Fail). When I submit the form a ArgumentError in InventoriesController#cart_update wrong number of arguments (1 for 2) error is returned. Parameters being passed:
{"commit"=>"cart_update",
"_method"=>"put",
"authenticity_token"=>"sH1tWXTJPltpSq5XaAkww7259IR5ZiflnqSFB2Zb0IY=",
"id"=>"50",
"cart_item"=>{"quantity"=>"16",
"id"=>"50"}}
You are getting the wrong number of arguments error because you are passing one argument to #cart.increment_inventory_quantity in the controller method. That method requires two arguments.
# In your controller:
def cart_update
#inventory = Inventory.find(params[:id])
#cart = find_cart
#cart.increment_inventory_quantity(params[:inventory]) # you are passing one thing
end
# Then in your model:
def increment_inventory_quantity(id, quantity) # the method wants two things
# ...
Possibly you intended to do something like this:
def cart_update
#inventory = Inventory.find(params[:cart_item][:id])
#cart = find_cart
#cart.increment_inventory_quantity(#inventory.id, params[:cart_item][:quantity])
end
Are you sure it's form_for( #cart.items ) and not form_for( item )?

Resources