i am using rails 4 and i have problem in nested form. i have used nested form in my application and through it values are getting stored properly into the database. i have used strong parameters properly. but the problem is that when i am updating the same form the nested fields values are not getting displayed in the respected text boxes.how to fix this issue?
this is what i have used in my controller
def vendor_info_params
params.require(:vendor_info).permit(:name, :primary_contact_name, :phone, :address, :city,
:vendor_references_attributes=>[:id, :vendor_info_id, :name, :email])
end
and this is what i have used in my _form.html.erb
<%= f.fields_for :vendor_references, #vendor_info.vendor_references.build do |builder| %>
<%= render "vendor_references", :f => builder %>
<% end %>
You specify a collection in your fields_for : #vendor_info.vendor_references.build
The build method is an alias of new so your collection contains only one new vendor reference. If you want to see all your references just do :
<%= f.fields_for :vendor_references, #vendor_info.vendor_references do |builder| %>
<%= render "vendor_references", :f => builder %>
<% end %>
If you need a new reference for each update or new call, you can add it in your controller method like :
def new
#vendor_info = VendorInfo.new
#vendor_info.vendor_references.build
end
Related
I'm learning Ruby on Rails at the moment and we're making a blog app to learn about crud actions and such and I'm stuck on this create method in my controller not working as it does in the course. I'm having trouble the create method in this controller:
class ArticlesController < ApplicationController
def show
#article = Article.find(params[:id])
end
def index
#articles = Article.all
end
def new
end
def create
#article = Article.new(params.require(:article).permit(:title, :description))
#article.save
redirect_to #article
end
end
I get this error when trying to create an article:
ActionController::ParameterMissing in ArticlesController#create
param is missing or the value is empty: article
It seems to be getting hung up on the first line of the create method but I'm not sure why it doesn't think there's an article... Here's my new article view as well for further reference:
<h1>Create a new Article</h1>
<%= form_with scope: #article, url: articles_path, local: true do |f| %>
<p>
<%= f.label :title %><br/>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :description %><br/>
<%= f.text_area :description %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
Check whether your parameters coming under hash with key article like this -
{"article"=>{params}}
Also initiate Article object in new action.
You can redefine the params to permit like this:
in controller new method create object
#article = Article.new
and in form HTML add one more option use method: "post"
I'm using the Rails SimpleForm gem to create forms. I realize a boolean field named "accepts" (which typically displays as a checkbox) can be displayed as a pair of radio buttons instead, by changing
<%= f.input :accepts %>
to
<%= f.input :accepts, as: :radio_buttons %>
However, I am using a generic form template to dynamically generate a form for any Rails model in a loop like this:
<% some_rails_model.attribute_names.each |attr| %>
<% f.input attr %>
<% end %>
Since I don't know whether a particular attribute is a boolean (as opposed to a string, integer, etc.), I don't know when to add as: :radio_buttons.
Is there a way to make ALL booleans default to being displayed as radio buttons?
Alternatively, is there some simple way to check whether attr is a boolean, so that I then know when to add as: :radio_buttons?
I found a solution, which involves checking in the model whether a particular field is a boolean or not:
<% some_rails_model.attribute_names.each |attr| %>
<% if some_rails_model.columns_hash[attr].type == :boolean %>
<%= f.input attr, as: :radio_buttons %>
<% else %>
<%= f.input attr %>
<% end %>
<% end %>
I am having trouble accessing a method i have written in a class, the problem is im trying to access it within an instance of that class, but would appreciate someone explain in a bit more details as to why this doesn't work and things to look at to get a solution.
I have created a simple helper method to use in my view to join two attributes
class TeamMember < ActiveRecord::Base
def fullname
"#{self.forename} #{self.surname}"
end
end
Within my view (show action) I want to be able to use this method
def show
#team_member = TeamMember.find(params[:id])
end
So doing this for example gives me an undefined method
<%= link_to fullname(#team_member) %>
OR
<% #team_member.each do |t| %>
<%= link_to fullname, t %>
<% end %>
Whereas this works
<% #team_member.each do |t| %>
<%= link_to "#{t.forename} #{t.surname}", t %>
<% end %>
Could someone help to clarify this for me so that i can learn from it please
You defined fullname method in your TeamMember class, but you try to call this method with implicit receiver in view, which is ActionView::Base instance. Instead, you should use explicit receiver, which must be TeamMember instance:
<%= link_to #team_member.fullname, #team_member %>
and:
<%= link_to t.fullname, t %>
In order to remove (paperclip) images from my objects, I have a custom callback (and route) defined:
ActiveAdmin.register Camping do
#...
member_action :destroy_image, :method => :delete do
camping = Camping.find(params[:id])
camping.image.destroy
redirect_to({:action => :show}, :notice => "Image deleted")
end
end
This works as expected; trough a named route destroy_image_admin_camping => /admin/campings/:id/destroy_image.
The problem is that I cannot find how to add this to the form:
ActiveAdmin.register Camping do
form do |f|
f.inputs "Camping" do
f.input :name
f.input :image
f.action :delete_image, :url => destroy_image_admin_camping_path(#camping.id), :button_html => { :method => :delete }
f.input :description
end
f.actions
end
#...
end
More detailed: I don't know how to pass the "id of the current item we are editing" into destroy_image_admin_camping_path; #camping is nil, f.camping not defined and so I don't know how to pass the item in there.
Is this the right approach? I prefer this "ajax-ish" interface over a more common checkbox-that-deletes-images-on-update, but I am not sure if this will work at all.
There's a few questions here, I'll try to address them all.
How to access the "id of the current item we are editing"
You are pretty close in looking for f.camping. What you want is f.object, so:
destroy_image_admin_camping_path(f.object.id).
NOTE: f.object.id will be nil when it's a new form (as opposed to an edit form), you'll want to check for that with unless f.object.new_record?
"Is this the right approach?"
I'm not sure, really. To me it seems like making requests without actually saving the currently rendered form could create complications, but it might turn out to be a better interface. Anyway, if you want to do the checkbox-that-deletes-images-on-update, this should help you out: Rails Paperclip how to delete attachment?.
However, if you want the ajax-ish approach I think you'll want an <a> tag styled as a button. The problem with actually using a button is that you don't want to submit the form.
Here's an example:
f.inputs do
link_to 'Delete Image', delete_image_admin_camping_path(f.object.id), class: 'button', remote: true, method: :delete
end
remote: true will make it an ajax request and ActiveAdmin gives you a pretty reasonable button class for <a> tags. Updating the interface based on success / failure is left as an exercise to the reader.
Also, you'll probably want to use erb templates for this instead of the Active Admin DSL (see http://activeadmin.info/docs/5-forms.html at the bottom).
Like this:
# app/views/admin/campings/_form.html.erb
<%= semantic_form_for [:admin, #post] do |f| %>
<%= f.inputs do %>
<%= f.input :name %>
<%= f.input :image %>
<%# Actually, you might want to check for presence of the image, I don't know Paperclip well enough to demonstrate that though %>
<% unless f.object.new_record? %>
<%= image_tag f.object.image_url %>
<%= link_to 'Delete Image', delete_image_admin_camping_path(f.object.id), class: 'button', remote: true, method: :delete %>
<% end %>
...
<% end %>
<%= f.actions %>
<% end %>
I am relative newbie to all this, so sorry if this sounds mad!
I have used this tutorial: http://www.railsmine.net/2010/03/rails-3-action-mailer-example.html
And I have a new contact form working great.
The controller is at app/controllers/support_controller.rb
class SupportsController < ApplicationController
def new
# id is required to deal with form
#support = Support.new(:id => 1)
end
def create
#support = Support.new(params[:support])
if #support.save
redirect_to('/', :notice => "Support was successfully sent.")
else
flash[:alert] = "You must fill all fields."
render 'new'
end
end
end
And the model at /app/models/support.rb
class Support
include ActiveModel::Validations
validates_presence_of :email, :sender_name, :support_type, :content
# to deal with form, you must have an id attribute
attr_accessor :id, :email, :sender_name, :support_type, :content
def initialize(attributes = {})
attributes.each do |key, value|
self.send("#{key}=", value)
end
#attributes = attributes
end
def read_attribute_for_validation(key)
#attributes[key]
end
def to_key
end
def save
if self.valid?
Notifier.support_notification(self).deliver!
return true
end
return false
end
end
The views however only work in views/supports/new.html.rb (rendered - views/supports/_form.html.erb)
So I can call the Model / Controller from localhost:3000/support/new but if I try and render the same form in another view from the root directory e.g. app/view/contact.html.erb I get:
undefined method `model_name' for NilClass:Class
I think this is because it is calling the support model away from the supports directory.
Do I have to create an instance on #support so it can be called? If so what is the best way of doing that? I think I am nearly there. I just want the contact form on multiple pages not just in suppport/new
Thanks
Charlie
Yes, you would need to create a #support variable in each action you wish to render your form.
Another option would be to refactor the form to take a parameter, that way you're a bit more flexible. For example, from your view:
<%= render :partial => "supports/form", :locals => {:support => #support} %>
Now, instead of referring to #support in your _form.html.erb, you'd refer to simply support as it's a local_assign.
Yet another option would be to refactor the form a little further, and worry about creating the actual form tag outside of the partial.
Such as:
app/views/supports/new.html.erb
<%= form_for #support do |form| %>
<%= render :partial => "suppports/form", :object => form %>
<% end %>
app/views/supports/_form.html.erb
<%= form.text_field :foo %>
<%= form.text_field :bar %>
...
In this case, when you render a partial with the object option, you will get a local variable in your partial with the same name as the partial. You maintain a little bit more flexibility in the path of your form, but can still render the meat of what a Support object is inside of the form while remaining consistent across your app.
To clarify, you could use this somewhere else by doing something like:
app/views/foos/_create_foo_support.html.erb
<%= form_for #foo.support do |form| %>
<%= render :partial => "supports/form", :object => form %>
<% end %>
You have to pass #support object wherever you use your contact form. It's working in SupportsController#new because you initialize the variable there. In all other places where you want to use the form, you'll have to do the same.