Avoiding eval when building radio buttons in rails - ruby-on-rails

Here, I am building database driven radio buttons. I wanted to know if there is a way I can avoid eval and see checked is true or not !Thanks,
Index Controller
columns = Model.column_names
View in haml
- columns.each do |cols|
- check = "c[0].#{cols}==1? true : false" // checking value here
- negcheck = "c[0].#{cols}==0? true : false"// checking value here
- pluckid = "c[0].id"
- id = eval(pluckid)
%tbody
%td #{cols}
%td
= label_tag 'On'
= radio_button_tag("ABC",1,checked = eval(check), options = {})
= label_tag 'Off'
= radio_button_tag("xyz",0,checked = eval(negcheck), options = {})

You can use the [] method to access the value.
- columns.each do |cols|
- check = c[0][cols] == 1
- negcheck = c[0][cols] == 0
- id = c[0].id
%tbody
%td #{cols}
%td
= label_tag 'On'
= radio_button_tag("ABC", 1, checked = check, options = {})
= label_tag 'Off'
= radio_button_tag("xyz", 0, checked = negcheck, options = {})

eval("c[0].#{cols}==1? true : false")
can be written as
c[0].send(cols) == 1

Related

Rails loop through data fields error

I'm trying to run a median calculation on data fields.
Each Glaze has the following decimal fields: "k2o", "na2o", "cao", "bao", "mgo", "sro".
I want to write a method to calculate the median of each datafield using the entire database of Glazes but I don't want to write individual methods for each oxide.
My plan was to loop through them using an array of the oxide names. I defined an array called #oxides = ["k2o","n2o","cao","bao","mgo","sro"].
View:
<% #oxides.each do |oxide| %>
<%= oxide %> median: <%= median(oxide) %><br/>
<% end %>
Controller:
def median(oxide)
g = Glaze.all
array = g.map { |g| g.oxide.to_s.to_f.round(3) }
sorted = array.sort
len = sorted.length
(sorted[(len - 1) / 2] + sorted[len / 2]) / 2.0
end
helper_method :median
This returns an error:
unknown method 'oxide'
If I substitute k2o in place of oxide in the array then it works fine. I'm not familiar enough with variable types but I guess it is looking for a method because no oxide field exists.
How can I force it to look for the value of oxide so that I can easily loop through g.k2o...,g.na2o...,g.cao...etc. ?
The Glaze class does not have an instance method oxide, but instead has 5 methods k2o, na2o, cao, bao, mgo, sro. In
array = g.map { |g| g.oxide.to_s.to_f.round(3) }
the inner g is an instance of Glaze, so it will fail when you call g.oxide. If you want to do the same to all fields, i.e.
k2o_array = g.map { |g| g.k2o.to_s.to_f.round(3) }
na2o_array = g.map { |g| g.na2o.to_s.to_f.round(3) }
cao_array = g.map { |g| g.cao.to_s.to_f.round(3) }
bao_array = g.map { |g| g.bao.to_s.to_f.round(3) }
mgo_array = g.map { |g| g.mgo.to_s.to_f.round(3) }
sro_array = g.map { |g| g.sro.to_s.to_f.round(3) }
then you need public_send:
OXIDES = [:k2o, :na2o, :cao, :bao, :mgo, :sro]
def median(oxide)
med = Hash.new
OXIDES.each do |oxide|
values = Glaze.all.map do |glaze|
glaze.public_send(oxide).to_s.to_f.round(3)
end
values.sort!
len = values.length
med[oxide] = (values[(len - 1) / 2] + values[len / 2]) / 2.0
end
return values
end
helper_method :median
which will give you
{:k2o=>1.111, :na2o=>2.222, :cao=>3.333, :bao=>4.444, :mgo=>5.556, :sro=>6.667}
Note that I store the oxide list in a constant instead of an instance variable because it never changes.

rake db:seed_fu not populating database

I'm using the seed-fu gem and am able to get 2 files to seed the db successfully. The following file, while it produces output in the terminal, isn't populating the db:
# residents.rb
Resident.seed do |r|
r.account_id = 1
r.employee_id = 1
r.first_name = "solomon"
r.last_name = "gibsom"
r.gender = "Male"
r.dob = Date.parse("1937-02-20")
r.case_number = "H-3827-JKZ-0329"
r.veteran_status_number = "G-15 classified"
r.marital_status = "Married"
r.arrival_date = Date.today
r.religious_preferences = "None"
r.insurance_info = "Medicaid"
r.burial_provisions = "Cremation"
r.admission_weight = "121 lbs"
r.admission_height = "5ft 9in"
r.allergies = "Corn, wheat and peanut allergies"
end
Address.seed do |r|
r.account_id = 1
r.employee_id = 1
r.resident_id = 1
r.street_address = "55298 solomon hills blvd"
r.city = "Flint"
r.state = "MI"
r.zip = "48289"
end
PrimaryPhone.seed do |r|
r.account_id = 1
r.employee_id = 1
r.resident_id = 1
r.area_code = "810"
r.number = "565-0255"
end
Terminal output:
The output looks good so I check for the records in the console:
I'm sort of at a loss on where further to look to check for errors.
Here are two files that work as expected:
#accounts.rb
Account.seed do |a|
a.facility_name = "Chuck Norris AFC"
end
#admins.rb
Employee.seed do |a|
a.account_id = 1
a.is_admin = true
a.first_name = "kenneth"
a.last_name = "the paige"
a.email = "test#example.com"
a.password = "12345678"
a.password_confirmation = "12345678"
a.dob = Date.parse("1965-05-05")
a.gender = "Male"
end
Address.seed do |address|
address.account_id = 1
address.employee_id = 1
address.street_address = "123 Chuckleburger dr."
address.city = "New York"
address.state = "NY"
address.zip = "00001"
end
some background:
I'm using seed-fu ~>2.3,
residents.rb lives inside of db/fixtures/, and the rails version is 4.2
Thank you in advance for having a look!
Pay attention to the SQL queries printed in the console when you run Resident.all: they have condition WHERE resident.account_id is NULL. But in seeds file Resident has account_id = 1.
You might've set default_scope for Resident model. Try running Resident.unscoped.all or remove the default scope.

Why is ruby's '.each' giving different results to using 'for'?

I am trying to switch a for x in y loop to a each_with_index. First, I am trying to switch from for to each. The code before is
...
- row_bg_color_group = 'row_color_group_1'
- for link in #links
- construct_hyperlink(link.url_address, link.alt_text)
- if link.group.group_name != (current_group ||= '')
- display_group = current_group = link.group.group_name
- row_bg_color_group = rotate_rows_color_group
- else
- display_group = ''
%tr{:class => "#{row_bg_color_group}"}
%td
= link_to display_group, link.group, {"title" => link.group.group_description}
%td
%span#mainLink
= sanitize #address_url
%td= link.version_number
....
and rotate_rows_color_group is a helper in app/helpers. The code is
def rotate_rows_color_group
if session[:group_shading] == 'true' || params[:show]
cycle('row_color_group_1 color_group_1', 'row_color_group_2 color_group_2', 'row_color_group_3 color_group_3')
else
cycle('row_color_group_1', 'row_color_group_2', 'row_color_group_3')
end
end
The initial change I made is just to switch
- for link in #links
to be
- #links.each do |link|
This is changing my view from
to
The group name gets repeated. Is it a scope issue?
Since .each uses a block, any variable declared within it will be re-declared each time it is entered.
To avoid this, simply declare current_group outside the block:
...
- row_bg_color_group = 'row_color_group_1'
- current_group = ''
- #links.each do |link|
- construct_hyperlink(link.url_address, link.alt_text)
- if link.group.group_name != current_group
- display_group = current_group = link.group.group_name
- row_bg_color_group = rotate_rows_color_group
- else
- display_group = ''
%tr{:class => "#{row_bg_color_group}"}
%td
= link_to display_group, link.group, {"title" => link.group.group_description}
%td
%span#mainLink
= sanitize #address_url
%td= link.version_number
....

(Rubymotion) How can I do this custom view in Formotion?

I am struggling at the moment to make a custom Form with Formotion(Also I'm very new in Rubymotion). Maybe I have to try another framework or maybe not doing any framework at all....
I try to make this:
At this moment I created this in Formotion:
The problem is the Border between password and email. It has to start under the text field and not under the icon. It is a small change but I don't know how to do this with Formotion. Are those kind of things easy possible? Thanks in advanced!
Here is my code:
class LoginScreen < PM::FormotionScreen
title ""
def table_data
{
sections: [
{
title: "Login",
rows: [
{
title: "Email",
key: :email,
type: :email,
placeholder: "me#mail.com",
auto_correction: :no,
auto_capitalization: :none,
text_alignment: UITextAlignmentLeft
}, {
title: "Password",
key: :password,
type: :password,
placeholder: "required",
secure: true,
text_alignment: UITextAlignmentLeft
}
]
}
]
}
end
end
I overwritten the EmailRow to insert the icon
motion_require 'string_row'
module Formotion
module RowType
class EmailRow < StringRow
def build_cell(cell)
cell.selectionStyle = self.row.selection_style || UITableViewCellSelectionStyleBlue
field = UITextField.alloc.initWithFrame(CGRectZero)
field.tag = TEXT_FIELD_TAG
observe(self.row, "value") do |old_value, new_value|
break_with_semaphore do
update_text_field(new_value)
end
end
field.clearButtonMode = UITextFieldViewModeWhileEditing
field.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter
field.textAlignment = row.text_alignment || UITextAlignmentRight
field.keyboardType = keyboardType
field.secureTextEntry = true if row.secure?
field.returnKeyType = row.return_key || UIReturnKeyNext
field.autocapitalizationType = row.auto_capitalization if row.auto_capitalization
field.autocorrectionType = row.auto_correction if row.auto_correction
field.clearButtonMode = row.clear_button || UITextFieldViewModeWhileEditing
field.enabled = row.editable?
field.inputAccessoryView = input_accessory_view(row.input_accessory) if row.input_accessory
add_callbacks(field)
cell.swizzle(:layoutSubviews) do
def layoutSubviews
old_layoutSubviews
# viewWithTag is terrible, but I think it's ok to use here...
formotion_field = self.viewWithTag(TEXT_FIELD_TAG)
formotion_field.sizeToFit
field_frame = formotion_field.frame
field_frame.origin.x = self.textLabel.frame.origin.x + Formotion::RowType::Base.field_buffer * 2
field_frame.origin.y = ((self.frame.size.height - field_frame.size.height) / 2.0).round
field_frame.size.width = self.frame.size.width - field_frame.origin.x - Formotion::RowType::Base.field_buffer
formotion_field.frame = field_frame
end
end
if UIDevice.currentDevice.systemVersion >= "6.0"
field.swizzle(:setText) do
def setText(text)
r = old_setText(text)
self.sendActionsForControlEvents(UIControlEventEditingChanged)
r
end
end
end
field.font = BW::Font.new(row.font) if row.font
field.placeholder = row.placeholder
field.text = row_value
icon = UIImage.imageNamed("icons/mail.png")
icon_view = UIImageView.alloc.initWithImage(icon)
icon_view.setFrame(CGRectMake(20, 18, icon_view.frame.size.width, icon_view.frame.size.height))
cell.addSubview(icon_view)
cell.addSubview(field)
cell.textLabel.hidden = true
field
end
end
end
end
This was extremely easy in the end. Just add an image in cell.imageView in EmailRow.
added this line:
cell.imageView.image = UIImage.imageNamed("icons/mail.png")
cell.imageView.setFrame(CGRectMake(20, 18, cell.imageView.frame.size.width, cell.imageView.frame.size.height))
and you access the cell with the code below, for example:
cell = #form.table.visibleCell.first
I'd recommend disabling the built-in border entirely and adding a pseudo-border using a thin UIView. That way you can set the frame to position it in the right position and give it a backgroundColor of #E3E3E5k like in your mockup.

If equal requires string conversion to work?

It seems that #original_id and comment.id have to be converted to strings to compare equal, when I don't convert them to strings, the string in the else branch is returned. Why is this? And is there a way round it?
- if #original_id.to_s == comment.id.to_s
= "Matched"
- else
= "hi"
Context:
.comment{:class => "c" + nesting.to_s}
.profile
%img{:src => "/assets/profile_image_sample.jpg"}
.message
.username
- if comment.user.username.blank?
= comment.user.first_name
- else
= comment.user.username
= comment.content
.reply-link
= link_to "Reply to comment...", post_path(:original_id => comment.id)
= #original_id.to_s + "and" + comment.id.to_s
- if #original_id.to_s == comment.id.to_s
= "Matched"
- else
= "hi"
- if comment.replies.count > 0
- nesting = nesting + 1
- comment.replies.each do |comment|
= render "comment", :comment => comment, :nesting => nesting
One of those two variables is a string, while the other is a number.
A possible cause is that in the controller, all received (posted) parameters are strings. Without explicit conversion, you are passing this value to the view as a string.
And to answer your second question:
Convert #original_id to an integer when setting it in the controller:
#original_id = params[:original_id].to_i

Resources