I'm using rails 3.2.
I have many to many type of models.
Is there a way to set a "value" of a model to field_for.label?
Here's what I want to do.
Client model
class Client < ActiveRecord::Base
attr_accessible :name, :renewal_month1, :renewal_month10, :renewal_month11, :renewal_month12, :renewal_month2, :renewal_month3, :renewal_month4, :renewal_month5, :renewal_month6, :renewal_month7, :renewal_month8, :renewal_month9, :sales_person_id, :usable, :user_id, :licenses_attributes
has_many :licenses, :dependent => :destroy
has_many :systems, :through => :licenses
accepts_nested_attributes_for :licenses
end
License model
class License < ActiveRecord::Base
attr_accessible :amount, :client_id, :system_id
belongs_to :client
belongs_to :system
def system_name
self.system.name
end
end
System model
class System < ActiveRecord::Base
attr_accessible :name, :sort
has_many :clients
has_many :licenses
has_many :clients, :through => :licenses
end
In client controller I built license object for all system.
def new
#client = Client.new
#title = "New Client"
System.all.each do |system|
#client.licenses.build(:system_id => system.id)
end
respond_to do |format|
format.html # new.html.erb
format.json { render json: #client }
end
end
In _form.html.erb I use fieds_for for licenses
<%= f.fields_for :licenses do |ff| %>
<tr>
<td><%= ff.label :system_id %></td>
</td>
<td> <%= ff.number_field :amount %>
<%= ff.hidden_field :system_id %>
<%= ff.hidden_field :system_name %>
</td>
</tr>
<% end %>
Result I get is this
<tr>
<td><label for="client_licenses_attributes_0_system_id">System</label></td>
</td>
<td> <input id="client_licenses_attributes_0_amount" name="client[licenses_attributes][0][amount]" type="number" value="10" />
<input id="client_licenses_attributes_0_system_id" name="client[licenses_attributes][0][system_id]" type="hidden" value="1" />
<input id="client_licenses_attributes_0_system_name" name="client[licenses_attributes][0][system_name]" type="hidden" value="SYSTEMNAME" />
</td>
</tr>
I want the label to look like this.
<td><label for="client_licenses_attributes_0_system_id">SYSTEMNAME</label></td>
SYSTEMNAME is the value of the model SYSTEM.
I have a virtual attribute in LICENSE model defined as system_name.
I was able to get SYSTEMNAME in hidden_field so I think models and controllers are fine.
I just couldn't find out how to set the value of a model to label.
Why can't you use the following?
<%= ff.label :system_name %>
I think the next code should work as well
<%= ff.label :amount, ff.object.system_name %>
I can't test this, but I hope it will generate
<label for="client_licenses_attributes_0_amount">SYSTEMNAME</label>
Note, that it creates a label for amount field, so that when the user click on it, amount field will be focused.
Have you tried adding system_name to the label
<%= f.fields_for :licenses do |ff| %>
<tr>
<td><%= ff.label :system_id, :system_name %></td>
<td> <%= ff.number_field :amount %>
<%= ff.hidden_field :system_id %>
<%= ff.hidden_field :system_name %>
</td>
</tr>
<% end %>
Related
I have page that list the products available and I want the user to be able to indicate which quantity of each product he wants. I'm not sure what is the correct way to create the form. I have done this but I'm sure it's not the best way to do it...
<%= form_tag create_order_path, :method => :post do %>
<% #products.each do |product| %>
<input name="ads[<%= product.id %>][quantity]">
<% end %>
<input type="submit" name="commit" value="Pay"></input>
<% end %>
In my controller I have
#products = []
params[:ads].each do |ad|
if product[1][:quantity].to_i > 0
#products << [product[0], product[1][:quantity]]
end
end
My goal is to have a list of products ids and the quantities needed so that I can create an order with it. What would be the correct way to do this?
Product model
class Product < ApplicationRecord
has_and_belongs_to_many :orders, join_table: PurchaseProduct.table_name
has_many :purchase_products
end
Order Model
class Order < ApplicationRecord
has_and_belongs_to_many :products, join_table: PurchaseProduct.table_name
has_many :purchase_products
accepts_nested_attributes_for :purchase_products
end
PurchaseProduct Model
class PurchaseProduct < ApplicationRecord
belongs_to :product
belongs_to :order
validates :quantity, length: { minimum: 1 }
end
Order Form
...
<%= form.fields_for :purchase_products do |another_form| %>
<div class="field">
<table>
<tr>
<td>
<%= another_form.label :product %>
<%= another_form.select(:product_id, Product.all.collect {|p| [ p.name, p.id ] }, ) %>
</td>
<td>
<%= another_form.label :quantity %>
<%= another_form.number_field :quantity %>
</td>
</tr>
</table>
</div>
<% end %>
...
For render x times product and quantity x.times { #order.purchase_products.build }
See full steps to build this here
I've successfully implemented one level of nested form with Cocoon and tables. However, I'm having a difficult time wrapping my mind on how to do another nested level. My issue is how to do this with a table. And maybe a table isn't the write way to go at all. Thank you for helping a newbie.
Here are my models:
class Profession < ApplicationRecord
has_many :procedure_categories, dependent: :destroy
accepts_nested_attributes_for :procedure_categories, allow_destroy: true
end
And:
class ProcedureCategory < ApplicationRecord
belongs_to :profession
has_many :procedures
accepts_nested_attributes_for :procedures, allow_destroy: true
end
And:
class Procedure < ApplicationRecord
belongs_to :procedure_category
end
Here is my top level form code:
<%= form_for(#profession) do |f| %>
<%= render 'shared/profession_error_messages' %>
<%= f.label :profession %>
<%= f.text_field :profession, class: 'form-control' %>
<%= f.label :description %>
<%= f.text_field :description, class: 'form-control' %>
<%= f.label :active, class: "checkbox inline" do %>
<%= f.check_box :active %>
<span>Active profession?</span>
<% end %>
<table class='table'>
<thead>
<tr>
<th>Category</th>
<th>Description</th>
<th>Display Order</th>
<th>Selection Type</th>
<th>Delete</th>
<th>Edit</th>
</tr>
</thead>
<tbody class="categories">
<%= f.fields_for :procedure_categories do |procedure_category| %>
<%= render 'procedure_category_fields', f: procedure_category %>
<% end %>
</tbody>
</table>
<%= link_to_add_association 'Add Category', f, :procedure_categories,
data: { association_insertion_node: '.categories', association_insertion_method: :append } %>
<br><br>
<%= f.submit "Save", class: "btn btn-primary" %>
<% end %>
And the next partial one level down:
<tr class="nested-fields">
<td><%= f.text_field :category, class: 'form-control' %></td>
<td><%= f.text_field :description, class: 'form-control' %></td>
<td><%= f.text_field :display_order, class: 'form-control' %></td>
<% cs = options_for_select(controls, f.object.selection_type) %>
<td><%= f.select :selection_type, cs, class: 'form-control' %></td>
<td><%= link_to_remove_association "Remove Category", f %></td>
<% if f.object != nil %>
<td><%= link_to "Category", edit_procedure_category_path(#profession,f.object) %><td></td>
<% end %>
</tr>
So, I'm struggling with how to implement the final level of nesting (procedures).
Thank you for listening.
Use has_many :through
Here are my models:
class Profession < ApplicationRecord
has_many :procedures, through: categories
has_many :categories, dependent: :destroy
accepts_nested_attributes_for :categories, allow_destroy: true
end
Rename this procedure_category model in category
class Category < ApplicationRecord
belongs_to :profession
has_many :procedures
accepts_nested_attributes_for :procedures, allow_destroy: true
end
And:
class Procedure < ApplicationRecord
belongs_to :category
end
If I miss something you can check the instruction from the rails guide
The controller professions#new action should create the following variables, so that they are available in the view:
def new
#profession = Profession.new
#categories = #profession.categories.build
#procedures = #categories.procedures.build
end
The view uses that variable so store the user inputs and make a post request at /profession/ with those inputs stored in the parameters hash
<%= form_for(#profession) do |f| %>
<%= f.fields_for :categories do |category| %>
<%= category.fields_for :procedures do |precedure| %>
<% end %>
<% end %>
<% end %>
The fields_for yields a form builder. The parameters' name will be what accepts_nested_attributes_for expects. For example, when creating a user with 2 addresses, the submitted parameters would look like:
This is how your parameters should look like:
{
'profession' => {
'name' => 'John Doe',
'categories_attributes' => {
'0' => {
'kind' => 'Home',
'street' => '221b Baker Street',
'procedures_attributes' => {
'0' => {},
'1' => {}
}
},
'1' => {
'kind' => 'Office',
'street' => '31 Spooner Street'
}
}
}
}
so make sure your form is pointing at post url /professions/ and that the routing will trigger the professions#create action
def create
binding.pry
end
for any problems set a binding pry and check in your console how your parameters are showing up.
Read more at
http://guides.rubyonrails.org/form_helpers.html#building-complex-forms
I have more curious questions for all you amazing people!
I am creating a forum and when you create a topic, you are also creating the first post at the same time.
I need to assign variables to certain fields.
Example: :user_id => current_user.id,
I don't have the param settings correct, so many of the fields are NULL when stored in the database.
Models
class Topic < ActiveRecord::Base
belongs_to :forum
has_many :posts, :dependent => :destroy
belongs_to :user
accepts_nested_attributes_for :posts
end
class Post < ActiveRecord::Base
belongs_to :topic
belongs_to :user
end
Topics Controller
# GET /topics/new
def new
#topic = Topic.new
#topic.posts.build
end
def create
#topic = Topic.new(topic_params)
if #topic.save
##topic.responses = Post.new(params[:responses])
flash[:success] = "Topic Posted"
redirect_to "/forums/#{#topic.forum_id}"
else
render :new
end
end
def topic_params
# last_post_at = (:last_post_at => Time.now)
params.require(:topic).permit(
:name,
:description,
[:last_poster_id => current_user.id],
[:last_post_at => Time.now],
[:user_id => current_user.id],
:forum_id,
posts_attributes: [:id, :content, :topic_id, :user_id => current.user.id] )
end
Post Controller
# GET /posts/new
def new
#post = Post.new
end
def create
#post = Post.new(
:content => params[:post][:content],
:topic_id => params[:post][:topic_id],
:user_id => current_user.id)
if #post.save
#topic = Topic.find(#post.topic_id)
#topic.update_attributes(
:last_poster_id => current_user.id,
:last_post_at => Time.now)
flash[:notice] = "Successfully created post."
redirect_to "/topics/#{#post.topic_id}"
else
render :action => 'new'
end
end
_form for View/Topic
<%= form_for(#topic) do |f| %>
<% if params[:forum] %>
<input type="hidden"
id="topic_forum_id"
name="topic[forum_id]"
value="<%= params[:forum] %>" />
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_field :description %>
</div>
<%= f.fields_for :posts do |p| %>
<%= p.label :content %><br />
<%= p.text_area :content %>
<% end %>
<%= f.submit :class => "btn btn-primary" %>
<% end %>
You'll likely be looking for a function called:
accepts_nested_attributes_for
You put this into the model you're working with (in your case Post) and it will pass paeans for the nested model through to the corresponding controller
There is a good RailsCast about this and I've gr some experience with it too. If you want me to post working live code, let me know (I'm on my iPhone)
Live Code
Models
#app/models/image_post.rb
belongs_to :post, :class_name => 'Post'
belongs_to :image, :class_name => 'Image'
accepts_nested_attributes_for :image, :allow_destroy => true
#app/models/post.rb
has_many :images, -> { uniq }, :class_name => 'Image', :through => :images_posts, dependent: :destroy
has_many :images_posts, :class_name => 'ImagePost'
accepts_nested_attributes_for :images_posts, :allow_destroy => true
Controller
def new
#post = Post.new
#post.images_posts.build.build_image
end
def create
#Using Inherited Resources Gem
create!
end
private
def permitted_params
{:post => params.require(:post).permit(:title, :body, images_posts_attributes: [:caption, image_attributes: [:image]] )}
end
Form
<%= form_for [:admin, resource], :html => { :multipart => true } do |f| %>
<table class="resource_table">
<thead>
<th colspan="2"><%= params[:action].capitalize %> <%= resource_class %></th>
</thead>
<tbody class="form">
<% attributes.each do |attr| %>
<tr class="<%= cycle('odd', '')%>">
<td><%= resource_class.human_attribute_name(attr) %></td>
<td>
<% if attr == "body" %>
<%= f.text_area attr, :rows => 60, :cols => 80, :class => "redactor" %>
<% else %>
<%= f.text_field attr, :value => resource.public_send(attr).to_s %>
<% end %>
</td>
</tr>
<% end %>
<%= f.fields_for :images_posts do |images_posts| %>
<%= images_posts.fields_for :image do |images| %>
<tr>
<td>Image</td>
<td><%= images.file_field :image %></td>
</tr>
<% end %>
<tr>
<td>Caption</td>
<td><%= images_posts.text_field :caption %></td>
</tr>
<% end %>
<tr class="dull">
<td colspan="2"><%= f.submit "Go" %></td>
</tr>
</tbody>
</table>
<% end %>
Use accepts_nested_attributes
class topic
accepts_nested_attributes :posts
end
class post
accepts_nested_attributes :topic
end
Then in form you can use fields_for posts while creating topic form
Also in post form fileds_for for topic
You may want to fetch the post params as
params[:topic].fetch(:post_attributes, nil)
Rails 4 has been sanitized the mass-assignment to be called as strong_params
Example
I have a nested table called products nested under the parties table and one of the comluns is "brand". A product has a quantity, color and "brand". For "brand" I want the user to be able to do a multiple selection and collection on as many brands as the users want per product. How would I do this? I installed the "rails chosen gem", but it seems I need allot more than that.
Is it even possible for one column in a table to have multiple collection per user and product? Also it seems I should use indexing?
Code:
Product.rb:
class Product < ActiveRecord::Base
attr_accessible :party_id, :party, :id, :brand, :color, :name, :quantity
belongs_to :party
BRAND_TYPES = ["Hugs", "Kisses", "Love" ]
end
Party.rb:
class Party < ActiveRecord::Base
validates :user_id, presence: true
attr_accessible :name, :products_attributes, :products, :user_id
belongs_to :user
has_many :products
accepts_nested_attributes_for :products, allow_destroy: true
end
_product_fields.html.erb:
<table>
<tr>
<td> <%= f.label :name, "Product Name" %> </td>
<td> <%= f.text_field :name %> </td>
<td> <%= f.label :color, "Color" %> </td>
<td> <%= f.text_field :color %> </td>
<td> <%= f.label :Quantity, "Quantity" %> </td>
<td> <%= f.text_field :quantity %> </td>
<td> <%= f.label :brand, "Brand" %> </td>
<td> <%= f.select :brand, Product::BRAND_TYPES, :multiple => true %> </td>
<td> <%= f.link_to_remove "Remove this task" %></td>
</tr>
</table>
Thanks, I appreciate it.
I have the following models
class GymUser < ActiveRecord::Base
belongs_to :user
belongs_to :gym
end
class User < ActiveRecord::Base
has_many :gym_users
has_one :gym
attr_accessible :gym_users_attributes, :gym_users
accepts_nested_attributes_for :gym_users
end
I have a form for a new user, with a nested model gym_user. I want to make sure the user doesn't exist already. This is what I'm trying:
def create_member
#user = User.new(params[:user])
#user.generate_password
#dupe = User.find_all_by_email(#user.email)
if(#dupe)
#gym_user = GymUser.new(params[:user][:gym_users_attributes])
#gym_user.user_id = #dupe.id
elsif #user.save
#gym_user = #user.gym_users.order('created_at DESC').first
#gym = Gym.find(#gym_user.gym_id)
end
end
I know there's only one nested model here, but I can't figure out how to access those nested parameters.
Here's the form itself
<%= form_for #user, :as => :user, :remote => true, :url => { :controller => 'users', :action => 'create_member'} do |f| %>
<table border="0" cellpadding="10" cellspacing="0">
<tr>
<td colspan="2">
<%= f.label :name %><br />
<%= f.text_field :name %>
</td>
<td colspan="2">
<%= f.label :email %><br />
<%= f.text_field :email %>
</td>
</tr>
<% f.fields_for :gym_users do |builder| %>
<tr>
<td>
<%= builder.label :role_id, "Role" %><br />
<%= builder.collection_select(:role_id, #roles, :id, :name, {:include_blank => true}, {:onchange => "new_member_role_changed()"}) %>
<%= builder.hidden_field :gym_id, :value => #gym.id %>
</td>
<td>
<%= builder.label :item_id, "Membership Level" %><br />
<%= builder.collection_select(:item_id, #gym.membership_items, :id, :name, {:include_blank => true}) %>
</td>
<td>
<%= builder.label :has_monthly_billing, "Recurring Billing?" %><br />
<%= builder.radio_button :has_monthly_billing, "1" %>Yes
<%= builder.radio_button :has_monthly_billing, "0" %>No
</td>
<td>
<%= builder.label :billing_date %><br />
<%= builder.collection_select(:billing_date, (1..31).to_a, :to_s, :to_s, {:include_blank => true}) %>
</td>
</tr>
<tr>
<td colspan="4">
<%= f.submit %>
Cancel
</td>
</tr>
<% end %>
</table>
<% end %>
I found the answer. I'm not sure if this is the best way but it works
params[:user][:gym_users_attributes].values.first
Your association should be
has_one :gym, :through => gym_users
Also, can you post your form paramaters?
Your focus is on not allowing creation of duplicate users, and you are using email to verify this. You should rather use the helper
validates_uniqueness_of :email
in your User model. As you have a nested attribute, your object will be created only after Rails validates that a user with same email doesn't exist already.
I hope I understood your problem right.