I have an INCIDENT with an attached WITNESS.
I am trying to show a link to remove an attachment from a nested attribute, but my link is pulling the :id of the parent record (invoice.id) instead of the nested/child record (invoice.witness_id).
I know I'm doing something wrong in my routes or in calling the correct id number from the controller or view... any help is appreciated!
incident.rb
has_many :witnesses
accepts_nested_attributes_for :witnesses, :reject_if => :all_blank, :allow_destroy => true
witness.rb
belongs_to :incident
has_attached_file :statement
routes.rb
match 'witness/:id' => 'witnesses#remove_statement', via: [:get, :post], as: 'remove_statement'
witnesses_controller
def index
#witnesses = #incident.witnesses.all
end
def remove_statement
#witness = Witness.find(params[:id])
#witness.statement = nil
respond_to do |format|
if #witness.save
format.html { redirect_to :back, notice: 'Attachment was removed.' }
format.json { head :no_content }
else
format.html { redirect_to :back, error: 'Attachment could not be removed.' }
format.json { render json: #witness.errors, status: :unprocessable_entity }
end
end
end
private
def set_witness
#witness = #incident.witnesses.find(params[:id])
end
def witness_params
params[:witness].permit(:first_name, :last_name, :phone, :email, :statement, :incident_id)
end
_witness_fields partial
<div class="nested-fields">
<div class="form-group">
....
<%= link_to "Remove Attachment", remove_statement_path, :id => :witness_id %>
...
incidents/_form.html.erb
<%= form_for(#incident, html: { :multipart => true , class: 'form-horizontal' }) do |f| %>
<%= f.error_notification %>
<% if #incident.errors.any? %>
<div class="red">
<% #incident.errors.full_messages.each do |msg| %>
<%= msg %><hr>
<% end %>
</div>
<% end %>
.....
<!-- WITNESS SECTION -->
<div class="span6">
<hr>
<fieldset id="witnesses">
<%= f.fields_for :witnesses do |builder| %>
<%= render 'witness_fields', :f => builder %>
<% end %>
</fieldset>
<p class="links">
<%= link_to_add_association 'Add Witness/Contact', f, :witnesses, { class:"btn btn-primary" } %>
</p>
</div>
</div>
<!-- END WITNESSES SECTION -->
.....
In your _withness_fields partial, you write
<%= link_to "Remove Attachment", remove_statement_path, :id => :witness_id %>
That should be something like
<%= link_to "Remove Attachment", remove_statement_path(f.object.id) %>
So two things: the path helper remove_statement_path needs the id as a parameter, and secondly, you need to actually give it the correct id of the object for which you are currently rendering.
Please note, since you dynamically add these, for new records this will not be valid (since there is no idea).
So you will have to check if the record is a new_record? and only show that link if it is not (because then you will have a valid id). If it is not a new record, you can just use the cocoon helper to remove it.
Related
please try to understand my question:
when i shut down the webrick server and again restart it ,then in my index view file there are some records after starting server if i click on any of three option (show,edit,delete)it gives me error "undefined method id' for nil:NilClass" and for "show" option "undefined methodname' for nil:NilC"
but if i add new record then every thing works fine i dont know what is the error
this is delete file
<%= link_to("<< Back to List", {:action => 'index'}, :class => 'back-link') %>
<div>
<h2>Delete vendor</h2>
<%= form_for(:vendor, url: {action:'destroy', id: #vendor.id}) do |f| %>
<p>Are you sure you want to permanently delete this vendor?</p>
<p><%= #vendor.name %></p>
<div>
<%= submit_tag("Delete vendor") %>
</div>
<% end %>
</div>
and this is controller
class VendorController < ApplicationController
def index
#vendors=Vendor.all
end
def new
#initiate new vendor which hits back to create
#vendor=Vendor.new
end
def create
#vendor=Vendor.new(vendor_params)
if#vendor.save
flash[:notice]="vendor ceated"
redirect_to(action: 'index')
else
flash[:notice]="there is error"
render('new')
end
def show
#vendor=Vendor.find(params[:id])
end
def edit
#vendor=Vendor.find(params[:id])
end
def update
#vendor=Vendor.find(params[:id])
if #vendor.update_attributes(vendor_params)
flash[:notice]='record updated'
redirect_to(action:'index')
else
flash[:notice]='there is some error'
render('edit')
end
end
def delete
#vendor=Vendor.find(params[:id])
end
def destroy
#vendor=Vendor.find(params[:id]).destroy
if #vendor.destroy
redirect_to(action: 'index')
else
render('delete')
end
end
end
private
def vendor_params
params.require(:vendor).permit(:name ,:image_url)
end
end
this is edit
<%= link_to("<< Back to List", {:action => 'index'}) %>
<div>
<h2>update Vendor</h2>
<%= form_for(:vendor, :url => {:action => 'update', id: #vendor.id }) do |f| %>
<%= render(partial:"form" , locals: {f: f}) %>
<div class="form-buttons">
<%= submit_tag("Update vendor") %>
</div>
<% end %>
</div>
this is show
<%= link_to("<<BAck to main",{action:"index"}) %>
<div>
<h1>showing <%=#vendor.name %></h1>
<p><%=#vendor.image_url %></p>
</div>
Good to see you fixed the problem.
--
For the benefit of future visitors, the error was caused by your controller name being singular, rather than plural.
All controllers should be named in the plural; all models in the singular:
#app/models/vendor.rb
class Vendor < ActiveRecord::Base
end
#app/controllers/vendors_controller.rb
class VendorsController < ApplicationController
end
As an added recommendation, your forms could be tidied up considerably by using the #vendor variable:
#app/views/vendors/edit.html.erb
<%= form_for #vendor do |f| %>
This will auto-fill the path and method, depending on the construct of the object you've passed.
I have a rails 4 application that has an add page and and a edit page. You can add elements easily (there is no issues), but then when you go to edit those and click save, it adds the fields you added initially a second time.
Here is my _form.html.erb
<%= nested_form_for #store do |f| %>
<%= f.fields_for :products do |product_form| %>
<div class='field'>
<%= product_form.text_field :name %>
<%= product_form.hidden_field :_destroy %>
<%= link_to "REMOVE PRODUCT", '#', class: "remove_fields" %>
</div>
<% end %>
<p><%= f.link_to_add "Add PRODUCT", :products %></p>
<%= f.submit 'Save', :class => "primary small" %>
<% end %>
and my store.rb model:
class Store < ActiveRecord::Base
has_many :products, class_name: "StoreProduct"
accepts_nested_attributes_for :products, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
end
my update action in my controller looks like:
def update
respond_to do |format|
if #store.update(store_params)
format.html { redirect_to store_products_path(#store), notice: 'Store was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #store.errors, status: :unprocessable_entity }
end
end
end
What does store_params look like in your controller? If id isn't one of the permitted values, then you can start to see the nested models created as new records each time the update action occurs. You would want to have something like:
params.require(:store).permit(products_attributes: [:id, :name, :_destroy])
See the documentation on strong parameters for the nested_form gem.
I'm doing a Rails tutorial, and trying to figure out why this is happening.
I'm making a to-do list, and everytime I try and insert a record into my Todo model, I get the following:
Here is the new.html.erb view that this is from:
<h1>Add new item to your todo listM</h1>
<%= form_for #todo, :url=>todo_path(#todo) do |f| %>
<%= f.label :name %> <%= f.text_field :name%>
<%= f.hidden_field :done, :value => false %>
<%= f.submit "Add to todo list" %>
<% end %>
Here is index.html.erb from where the user is linked to new.html.erb
<h1>TASKS</h1>
<h3> TO DO </h3>
<ul>
<% #todos.each do |t| %>
<li>
<strong><%= t.name %></strong>
<small><%= link_to "Mark as Done", todo_path(t), :method => :put %></small>
</li>
<% end %>
</ul>
<h3> DONE </h3>
<ul>
<% #todones.each do |t| %>
<li>
<strong><%= t.name %></strong>
<small><%= link_to "Remove", t, :confirm => "You sure?", :method => :delete %></small>
</li>
<% end %>
</ul>
<%= link_to "Add new task", new_todo_path %>
Here is the TodoController I have managing these actions:
class TodoController < ApplicationController
def index
#todos = Todo.where(done:false)
#todones = Todo.where(done:true)
end
def new
#todo = Todo.new
end
def todo_params
params.require(:todo).permit(:name, :done)
end
def create
#todo = Todo.new(todo_params)
if #todo.save
redirect_to todo_index_path, :notice => "Your todo item was created!"
else
render "new"
end
end
def update
#todo = Todo.find(params[:id])
if #todo.update_attribute(:done, true)
redirect_to todo_index_path, :notice => "Your todo item was marked done!"
else
redirect_to todo_index_path, :notice => "Couldn't update your task"
end
end
def destroy
#todo = Todo.find(params[:id])
#todo.destroy
redirect_to todo_index_path, :notice => "Your todo item was deleted"
end
end
And finally the routes.rb
Oneday::Application.routes.draw do
devise_for :users
root 'home#index'
resources :todo
end
Any input as to why this is happening and how to rectify it would be great.
You do not comply with the rails convention. Use plural form for resources. Then, your action is correct.
TodosController, todos_controller.rb, resources :todos
( Rails use singular/plural format to support RESTful links and to recognize named actions )
This
<%= form_for #todo, :url=>todo_path(#todo) do |f| %>
will set (or leave) the form http method to get. You could change it to:
<%= form_for #todo, :url=>todo_path(#todo), method: :post do |f| %>
or even shorter, leave it to Rails to find out what method is needed:
<%= form_for #todo do |f| %>
I found a fix to this exact issue if anyone is still curious, i know its an old issue and an easy one at that, but still figured id solve it. the original route todo_path leads to todo#show. todo_index however is assigned to todo#index and todo#create so its what we want. the line should look like this:
<%= form_for #todo, :url => todo_index_url(#todo), method: :post do |f| %>
I encountered a similar issue with one of my applications and stumbled across this post as a fix. None of the suggestions worked for me, but i was able to fix it with a little tinkering on the routes.
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
I'm a rails newbie. I'm sure my question probably be answered with a line or two. I just cant figure out whats wrong. Please help! Thank you for your time in advance.
So here's my problem :
My controller method release_reservation is not able to save the attributes with new values in the database. With my limited rails knowledge I'm suspecting it has something to with routes.rb but I am not able to narrow down to the actual issue.
Here's release_reservation which is defined in reservations_controller.rb
def release_reservation
#reservation = Reservation.find(params[:id])
#reservation.reserve_from = DateTime.now
#reservation.reserve_to = DateTime.now
#reservation.reserve_status = false
respond_to do |format|
if #reservation.update_attributes(params[:reservation])
format.html {redirect_to release_reservation_reservation, :notice => 'Machine was successfully released' }# show.html.erb
format.json { render :json => #reservation }
else
format.html { render :action => "show" }
format.json { render :json => #reservation.errors, :status => :unprocessable_entity }
end
end
end
Here's the model Reservation.rb
class Reservation < ActiveRecord::Base
validates :machine_reserver, :presence => true, :length => { :maximum => 50 }
validates :machine_name, :uniqueness => {:scope => :machine_platform}
validate :check_reservation_end_date, :on => :update
validate :check_reservation_from_date
default_scope :order => 'updated_at DESC'
def date_reset
self.reserve_from = DateTime.now
self.reserve_to = DateTime.now
end
def check_reservation_end_date
if self.reserve_to < self.reserve_from
errors.add(:reserve_to, "cannot be lesser than or equal to start date")
end
end
def check_reservation_from_date
if self.reserve_from < DateTime.now
errors.add(:reserve_from, "cannot be lesser than current date & time")
end
end
end
Here's View file from where I want to call release_reservation
<h1>Reservation</h1>
<br>
<p>
<% if #reservation.reserve_to > DateTime.now %>
This machine will be released in
<% duration = #reservation.reserve_to - DateTime.now %>
<%= distance_of_time_in_words(duration) %>
<% end %>
</p>
<p>
<b>Machine name: </b>
<%= #reservation.machine_name %>
</p>
<p>
<b>Machine platform: </b>
<%= #reservation.machine_platform %>
</p>
<p>
<% if #reservation.reserve_to > DateTime.now %>
<b>Reserved by: </b>
<%= #reservation.machine_reserver %>
<% end %>
</p>
<p>
<% if #reservation.reserve_to > DateTime.now %>
<b>Reserve from: </b>
<%= #reservation.reserve_from.to_formatted_s(:long) %>
<% end %>
</p>
<p>
<% if #reservation.reserve_to > DateTime.now %>
<b>Reserve to: </b>
<%= #reservation.reserve_to.to_formatted_s(:long) %>
<% end %>
</p>
<div class="form-actions">
<%= link_to 'Back', reservations_path, :class => 'btn' %>
<% if #reservation.reserve_to > DateTime.now %>
<%= link_to 'Release', {:controller => 'reservations', :action => 'release_reservation', :id => #reservation}, :confirm => "Are you sure?", :class => 'btn btn-danger' %>
<% else %>
<%= link_to 'Reserve', edit_reservation_path(#reservation), :class => 'btn btn-primary' %>
<% end %>
Here's routes.rb
Reserver::Application.routes.draw do
resources :reservations do
member do
get 'release_reservation'
end
end
resources :machines
resources :reserves
resources :platforms
resources :users
root :to => 'reservations#index'
end
rake routes
release_reservation_reservation GET /reservations/:id/release_reservation(.:format) reservations#release_reservation
reservations GET /reservations(.:format) reservations#index
POST /reservations(.:format) reservations#create
new_reservation GET /reservations/new(.:format) reservations#new
edit_reservation GET /reservations/:id/edit(.:format) reservations#edit
reservation GET /reservations/:id(.:format) reservations#show
PUT /reservations/:id(.:format) reservations#update
DELETE /reservations/:id(.:format) reservations#destroy
I think your validations prevent instance from persisting