I have a rails3 form that allows the user to edit a list of answers, as part of an assessment.
I use a fields_for loop to generate each text input:
app/models/assessment.rb :
class Assessment < ActiveRecord::Base
serialize :answers, Hash # answers is a t.text field used to store all answers.
end
app/view/assessments/new.html.erb :
<p>Initialized answers: <%= #assessment.answers %></p>
<% item_counter = 0 %>
<% form.fields_for :answers do |answer_fields| %>
<% item_id = "item" + item_counter.to_s %>
<% item_counter = item_counter + 1 %>
<div class="field">
<%= answer_fields.label "the appropriate question, omitted for brevity" %>
<br/>
<% #assessment.answers[item_id] = "" %>
<%= answer_fields.text_field item_id, :value => #assessment.answers[item_id] %>
</div>
<% end %>
PROBLEM: The fields_for loop does zero iteration, no field gets printed.
( despite "Initialized answers:" showing correctly: {"a"=>143, "b"=>42} )
This should do. Tested locally.
<p>Initialized answers: <%= #assessment.answers %></p>
<% #assessment.answers.each do |key, value| %>
<%= form.fields_for :answers, #assessment.answers[key] do |answer_fields| %>
<div class="field">
<%= answer_fields.label key %>
<br/>
<%= answer_fields.text_field key, :value => value %>
</div>
<% end %>
<% end %>
Turns Hash to OpenStruct object solved my problem.
<% form.fields_for :answers, OpenStruct.new(answers) do |answer_fields| %>
<% item_id = "item" + item_counter.to_s %>
<% item_counter = item_counter + 1 %>
<div class="field">
<%= answer_fields.label "the appropriate question, omitted for brevity" %>
<br/>
<% #assessment.answers[item_id] = "" %>
<%= answer_fields.text_field item_id, :value => #assessment.answers[item_id] %>
</div>
Related
I am a beginner working on a RoR app that allows users to update their resume with experiences and education. I have two models for these different items and would like to display them together in chronological order. I want to know how to set this up in my profile controller and view.
I'd like to adopt this same practice to a separate part of the app that will combine post and discussion items from users in the same way. However, currently, my focus is on the experience and education portion.
profiles/show.html.erb:
<% if #experiences.any? or #educations.any? %>
<div class="postExpOuter">
<% #experiences.each do |experience| %>
<div class="postExp">
<div>
<h2><%= experience.position %></h2>
<h3><%= experience.company %> | <%= experience.location %></h3>
<h4>
<%= experience.start_month %> <%= experience.start_year %>
<% if experience.end_year %>
<%= " - " + experience.end_month %> <%= experience.end_year %>
<% else %>
<span> - Present</span>
<% end %>
</h4>
</div>
</div>
<% end %>
<% #educations.each do |education| %>
<div class="postExp">
<div>
<h2><%= education.degree %></h2>
<h3><%= education.school %></h3>
<h4>
<% if education.end_year %>
<span>Class of </span><%= education.end_year %>
<% else %>
<%= education.start_year %><span> - Present</span>
<% end %>
</h4>
</div>
</div>
<% end %>
</div>
<% end %>
just hacked in my browser, don't know if it works directly:
<%- (#experiences.to_a + #educations.to_a).sort_by(&:end_year).each do |item| -%>
<%- if item.is_a? Experience -%>
your markup here...
<%- else -%>
your other markup here...
<%- end -%>
<%- end -%>
haven't written ERB since... uhh, long. basically it's just the following: merge the 2 ActiveRecord-Relations as Arrays into one big Array, sort them by the timestamp you want (you may add .reverse at the end if you want). While iterating through the list, check the type of object you have.
Hope this helps.
profiles_controller.rb:
class ProfilesController < ApplicationController
def show
#user = User.find_by_profile_name(params[:id])
if #user
#posts = #user.posts.all(:order => "created_at DESC", :limit => 3)
#experiences = #user.experiences.all(:order => "start_year DESC")
#educations = #user.educations.all(:order => "start_year DESC")
#items = (#experiences.to_a + #educations.to_a).sort_by(&:start_year).reverse[0,3]
render action: :show
else
render file: 'public/404', status: 404, formats: [:html]
end
end
end
profiles/show.html.erb:
<% if #items.any? %>
<div class="postExpOuter">
<% #items.each do |item| %>
<% if item.is_a? Experience %>
<div class="postExp">
<div>
<h2><%= item.position %></h2>
<h3><%= item.company %> | <%= item.location %></h3>
<h4>
<%= item.start_month %> <%= item.start_year %>
<% if item.end_year %>
<%= " - " + item.end_month %> <%= item.end_year %>
<% else %>
<span> - Present</span>
<% end %>
</h4>
</div>
</div>
<%- else -%>
<div class="postExp">
<div>
<h2><%= item.degree %></h2>
<h3><%= item.school %></h3>
<h4>
<% if item.end_year %>
<span>Class of </span><%= item.end_year %>
<% else %>
<%= item.start_year %><span> - Present</span>
<% end %>
</h4>
</div>
</div>
<% end %>
<% end %>
</div>
<% end %>
I have Category and Products, Category has many product in it. I'm able to Edit Delete Create the Category, Also able to Create Delete Products in the Each Category, but want to Edit the each Product.
I can access the single Product of particular Category by using link_to , and product controller is receiving the the product of particular Category.
In html of Category where all Product belongs of that category has
<%= link_to 'Edit', edit_category_product_path(product.category, product) %>
Controller of Product, edit function is
#product = Product.where(params[:id])
then my edit html is
<%= form_for #product do |f| %>
<% if #product.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#product.errors.count, "error") %> prohibited this product from being saved:</h2>
<ul>
<% #product.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :price %><br />
<%= f.text_field :price %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
<%= link_to 'Back', category_products_path %>
I'm getting this error when try to Edit the product
NoMethodError in Products#edit
Showing C:/Sites/propoolpro6/app/views/products/edit.html.erb where line #3 raised:
undefined method `model_name' for ActiveRecord::Relation:Class
Extracted source (around line #3):
1: <h1>Editing product</h1>
2:
3: <%= form_for #product do |f| %>
4: <% if #product.errors.any? %>
5: <div id="error_explanation">
6: <h2><%= pluralize(#product.errors.count, "error") %> prohibited this product from being saved:</h2>
Rails.root: C:/Sites/propoolpro6
Application Trace | Framework Trace | Full Trace
app/views/products/edit.html.erb:3:in `_app_views_products_edit_html_erb___584392485_32651052'
Request
Parameters:
{"category_id"=>"1",
"id"=>"3"}
Note: i have used this 2, but same error,
<%= form_for(#product) do |f| %>
I think following line create array
#product = Product.where(params[:id])
which could not be used by the form_helper (expecting a Model name generally provided by an ActiveRecord Relation).you can inspect the #product to see the result.
so it is better if you use find instead of where like
#product = Product.find(params[:id])
I hope this answer would help you.
Thanks.
I have 3 models, Product, Variation and Color. I'm using the nested_form gem.
Product has_many :variations
Variation belongs_to :product
Variation has_and_belongs_to_many :colors
Color has_and_belongs_to_many :variations
Through Product form I have nested_form for Variations. I want to associate colors through checkbox but receive undefined local variable or method "color_ids"
Product model
def new
#product = Product.new
1.times { #product.variations.build }
end
def create
#product = Product.new(params[:product])
...
end
My form //edited//
<%= nested_form_for(#product) do |f| %>
<% if #product.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#product.errors.count, "error") %> prohibited this product from being saved:</h2>
<ul>
<% #product.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="inline-form">
<%= f.fields_for :variations %>
<p><%= f.link_to_add "Add a variation", :variations %></p>
</div>
<div class="actions">
<%= submit_or_cancel(f) %>
</div>
</div>
<% end %>
And nested form is a basic table with
<table id="new_item">
<tr>
<th>Name</th>
<th>Color</th>
</tr>
<tr>
<td><%= f.text_field :name, :size => 40 %></td>
<td><% for color in Color.all %>
<%= check_box_tag 'variation[color_ids][]', color.id, variation.color_ids.include?(color.id), :id => dom_id(color) %><%= label_tag dom_id(color), color.name, :class => "check_box_label" %>
<% end %>
</td>
</tr>
</table>
I'm guessing that your issue is the part of the form doing color_ids.include?(color.id). I'd need to see the rest of your form erb to tell you how to fix it.
It's going to be something like variation.color_ids.
Another thing to note, that style of for loop is odd to see in typical/idiomatic ruby.
This is more typical:
<% Color.all.each do |color| %>
<%= check_box_tag 'variation[color_ids][]', color.id, color_ids.include?(color.id), :id => dom_id(color) %><%= label_tag dom_id(color), color.name, :class => "check_box_label" %>
<% end %>
I'm playing with ActsAsTaggableOn in a small project to see what are the possibilities of this gem.
So I have Products and products can have tags.
In my Product _form
<%= form_for(#product) do |f| %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
Tags<br />
<% tag_cloud(#tags, %w(css1 css2 css3 css4)) do |tag, css_class| %>
<%= check_box_tag 'product[tag_list][]',tag.name,#product.tag_list.include? (tag),:class => css_class %>
<%= tag.name %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
In ProductController I have defined the tag_cloud method
def tag_cloud
#tags = Product.tag_counts_on(:tags)
end
So in my editing product, I can tag the product with the checkboxes, but if a product already has tags those checkboxes aren't selected. I assume that here #product.tag_list.include? (tag) I am missing something or doing something wrong.
Any ideas? Thanks for your help =)
Cheers.
Today, after reading more carefully, I found the answer to this one.
This line
<%= check_box_tag 'product[tag_list][]',tag.name,#product.tag_list.include? (tag),:class => css_class %>
should be
<%= check_box_tag 'product[tag_list][]',tag.name,#product.tag_list.include? (tag.name),:class => css_class %>
So instead of the object I want to check if that name exists in the list.
Hope this helps someone.
Am trying to display a 'total comments' number (i.e.7) count beside the article on the index page and not on the article page. Would like to use a ruby method for this as its probably the most straight forward...?
views/articles/_article.html.erb
<div class="article_header">
<b>Title: </b> <%= truncate(article.title, :length => 50) %>
by <%= article.user.username %> on <%= article.created_at.strftime("%d %B, %Y") %>
<b>Detail:</b> <%= truncate(article.body, :length => 225) %>
</div>
<br />
<%= blog.comments.count %>
<%= link_to 'Read', article %>
<% if can? :update, article %>
| <%= link_to 'Edit', edit_article_path(article) %> |
<% end %>
Pass in a variable when you call your partial:
= render "article", :display_count => true
Then in your partial:
<% display_count ||= false %>
<%= display_count ? blog.comments.count : '' %>
The correct way to do this would be:
<td><%= link_to "Comment count = #{article.comments.count}", article_path(article) %>
This will simply add another column to the output on your index page. It doesn't have to be linked if you simply want to display the count:
<td><%= "Comment count = #{article.comments.count}" %>