Rails radio button options hash - ruby-on-rails

My view:
<%= radio_button_tag "recommendation_ratings[#{rec.recommendation.id}][rating]", '3'%>
In my controller, I parse out these values:
input = params[:recommendation_ratings].values
input.each do |mini_params|
rating = mini_params[:rating]
recommendation_id = mini_params[:recommendation_id]
Using the rating variable I create a new records in the same controller action:
rate = Rating.new(
:rating => rating,
:label => rating_label)
How can I assign a rating to a rating_label when a new record is created. Example:
if rating == 1 rating_label = "Fair"
Should I do this in my controller, or can I add the rating_label to my radio_button_tag as another attribute?
UPDATE:
I tried a case statement in my controller but get an NoMethodError "Undefined Method Rating"
rating case
when rating == 1
rating_label = "Bad"
when rating == 2
rating_label = "Fair"
when rating == 3
rating_label = "Good"
else rating == 0
rating_label = "N/A"
end

Refactor your view code from using radio_button_tag to a fields_for block:
<%= fields_for :recommendation_ratings do |f| %>
<% f.hidden_field :id, rec.recommendation.id %>
<% f.radio_button :rating, 3 %>
<% end %>
Change your controller code to this:
selected_rating = params[:recommendation_ratings]
rating = selected_rating[:rating]
recommendation_id = selected_rating[:id]
And add a helper method somewhere as:
def rating_label(rating)
%w{N/A Bad Fair Good}[rating.to_i]
end
Now you can make a new Rating object like this:
rate = Rating.new(
:rating => rating,
:label => rating_label(rating))

Related

Replace params data from name to id before save in rails

How to replace item name to item id before save in database.
This is my controller code
def create
#supplier = Supplier.new(supplier_params)
if #supplier.save
item_code = params[:supplier_item][:item_ids]
item_id = Item.where(:item_code => item_code).pluck(:id)
item_params = params.require(:supplier_item).permit(item_ids: [], location_ids:[], supplier_prices: [])
items = item_params[:item_ids].zip(*item_params.values_at(:location_ids, :supplier_prices))
items.map do |item_id, location_id, supplier_price|
supplier_item = SupplierItem.new({
item_id: item_id,
location_id: location_id,
supplier_price: supplier_price,
supplier_id: #supplier.id
})
supplier_item.save
end
flash[:success] = "New supplier created"
redirect_to supplier_path(#supplier)
else
render 'new'
end
end
So this code now save item_ids["Apple", "Banana"]. But I want to save this in id form which is like this item_ids["1", "3"]
This is my view code
<%= f.label :item, class: 'required'%>
<% items = Item.where(company_id: current_user.company.id)%>
<%= text_field_tag "[supplier_item][item_ids][]", nil, {list: 'browser-item'} %>
<% items.each do |item| %>
<option data-value = <%= item.id %> value = <%= "#{item.item_code} - #{item.name}" %>></option>
<% end %>
So I try this to get item id of the item name
Item.where(:item_code => item_name).pluck(:id)
This one give me all the item id I were selected. So how should I replace this id into the params

Error with initial calculation of instance variable values in Rails controller

I'm looking to build a basic app that provides a score based on how enjoyable users found a given lunch.
In my view, the voting buttons look like this:
<%= form_for :lunch, url: upvote_lunch_lunch_path(params[:id]), method: :put, :html => {:class => 'form-inline'} do |f| %>
<%= f.hidden_field :liked %>
<%= f.hidden_field :id %>
<%= f.submit "Like Lunch", class: "btn btn-large btn-success" %>
<% end %>
<%= form_for :lunch, url: downvote_lunch_lunch_path(params[:id]), method: :put, :html => {:class => 'form-inline'} do |f| %>
<%= f.hidden_field :disliked %>
<%= f.hidden_field :id %>
<%= f.submit "Dislike Lunch", class: "btn btn-large btn-danger" %>
<% end %>
Displaying the value (in a partial) looks like this:
<%= number_to_percentage(#enjoy_score * 100, precision: 0, format: "%n") %>
and finally, in my "lunches" controller, I have the following:
def show
#lunch = Lunch.find(params[:id])
#provider = #lunch.provider
#total_enjoy_votes = (#lunch.liked + #lunch.disliked)
#enjoy_score = (#lunch.liked.to_f / #total_enjoy_votes)
end
def downvote_lunch
#lunch = Lunch.find(params[:id])
#lunch.increment!(:disliked)
redirect_to #lunch
end
def upvote_lunch
#lunch = Lunch.find(params[:id])
#lunch.increment!(:liked)
redirect_to #lunch
end
Everything works as expected, so long as the database already has values for liked and disliked against that particular lunch ID. If, for example, you are the first person to attempt to answer this question (lets say just after a lunch was created) the application errors out with the message "undefined method +' for nil:NilClass" at this line:#total_enjoy_votes = (#lunch.liked + #lunch.disliked)`
Two questions:
Why is it if I open the database (with sqlitebrowser) and "seed" a row of data with liked = 1 and disliked = 1 the methods will work as expected, but if I don't, it errors out? What should I do to "initialize" #lunch.liked and #lunch.disliked so that there isn't an error for the initial user?
(Bonus Point) How can I keep the controller code DRY so I don't have to type #lunch = Lunch.find(params[:id])
at the beginning of every method?
Thanks so much in advance. I apologize if this is a insanely simple question.
1.
#total_enjoy_votes = (#lunch.liked + #lunch.disliked) errors, because #lunch.liked is nil, since it is never set to anything, as well, as #lunch.disliked
To avoid this error you should check if liked and disliked are present.
liked = #lunch.liked ? #lunch.liked : 0
disliked = #lunch.disliked ? #lunch.disliked : 0
#total_enjoy_votes = (liked + disliked)
#enjoy_score = (liked.to_f / #total_enjoy_votes)
2.
before_filter :find_lunch!, only: [ :update, :destroy ] # list of actions where to perform the method.
private
def find_lunch!
#lunch = Lunch.find(params[:id])
end
EDIT
explanation to the line: #lunch.liked ? #lunch.liked : 0
It is ternary operator which comes in handy really often.
Syntax
boolean_expression ? true_expression : false_expression
Example
grade = 88
status = grade >= 70 ? "pass" : "fail"
#=> pass
It is the same, as if I wrote something like:
if #lunch.liked.nil?
liked = 0
else
liked = #lunch.liked
end
First approach:-
def show
#lunch = Lunch.find(params[:id])
#provider = #lunch.provider
liked = ((#lunch.liked.present? and #lunch.liked >= 0) ? #lunch.liked : 0)
#total_enjoy_votes = liked + ((#lunch.disliked.present? and #lunch.disliked >= 0) ? #lunch.disliked : 0)
#enjoy_score = (#total_enjoy_votes > 0 and liked > 0) ? (#lunch.liked.to_f / #total_enjoy_votes) : 0
end
Second approach:-
In Lunch model set a calback as
class Lunch < < ActiveRecord::Base
before_save :initialize_liked_disliked
private
def initialize_liked_disliked
if self.new_record?
self.liked = 0
self.disliked = 0
end
end
end
It will initialize both the fields with 0, then make the changes in controller as:
def show
#lunch = Lunch.find(params[:id])
#provider = #lunch.provider
#total_enjoy_votes = #lunch.liked + #lunch.disliked
#enjoy_score = (#total_enjoy_votes > 0) ? (#lunch.liked.to_f / #total_enjoy_votes) : 0
end

Validation by neighbor association attribute in rails

I have two models: Parent and Child, and i have a nested form for Parent, something like this:
= simple_form_for #parent do |form|
= form.input :name
= form.simple_fields_for :children do |children_form|
= children_form.input :money
= form.button :submit
What i need is a way to validate if sum of all children money equals to 100.
I've tried (in Parent):
validate do
total = children.inject(0) { |sum, child| child.money }
unless money == 100
children.each do |child|
child.errors.add(:money, :invalid)
end
end
end
but its not working for some reason. Thanks
Update:
Sorry, false alarm, i've used inject incorrectly.
total = children.inject(0) { |sum, child| sum + child.money }

Refactor and code placement

My edit action has a series of radio buttons in the view. I want to fill in the value of the currently selected field. I managed to get this to work, though I feel the code could be better and also perhaps should be in the model.
controller:
def edit
#rating = Rating.find(params[:id])
#a,#b,#c,#d,#e,#f,#g,#h,#i,#j = false
if #rating.environ == 1
#a = true
elsif #rating.environ == 2
#b = true
elsif #rating.environ == 3
#c = true
elsif #rating.environ == 4
#d = true
.
.
.
etc.
view:
1<%= f.radio_button :environ, 1, :checked => #a %>
2<%= f.radio_button :environ, 2, :checked => #b %>
3<%= f.radio_button :environ, 3, :checked => #c %>
.
.
etc..
What is your model code? I am guessing a rating has many environs?
In any case, you can just loop through all of them in the view and make your :checked argument a boolean.
something like
<% #environs.each do |env| -%>
<%= f.radio_button :environ, env.id, :checked => (#rating.environ == env) %>
<% end -%>

Rails problem display attribute key along with attributes value

I have the following problem. I have a form which takes input for a "Chart" object. But after processing the form, i wish to display one of the values, and it adds the key of this value.
Class model
class Chart
attr_accessor :title, :series
def initialize(title = nil, series = [])
#title, #series = title, series
end
end
View of form:
<% form_for :chart , :url => { :action => "show" } do |f| %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>...
<% end %>
Chart controller, show method:
def show
#chart = Chart.new(params[:chart])
end
View of show:
<h2><%=h #chart.title %></h2>
Which displays: "title"input_forms_title""
for example: writing in the input form: Economy, prints in the show view: "titleEconomy"
Any ideas?
I have just figured it out. The problem was in the constructor or initialize method. By changing the initialize method to:
def initialize( options = {} )
#title = options[:title]
#series = []
end
It now accepts all params perfectly!

Resources