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
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
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.
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
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>
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 )?