I have a form where I want a checkbox selection to override the user's selected value for another attribute.
The form:
<%= form_for(#foo) do |f| %>
<tr>
<th>FooType</th>
<td><%= f.select :foo_type_id, options_from_collection_for_select(FooType.order(:name).all, "id", "name", #foo.cabinet_type_id) %></td>
</tr>
<tr>
<th>Legacy Foo</th>
<td><%= f.check_box :is_legacy %> </td>
</tr>
Where do I put code to overwrite the user's selection for :foo_type based on if :is_legacy is checked? I tried adding an update_attribute command after saving the new Foo, but it doesn't seem to work:
if #foo.save_standard and ! row.nil?
#set foo type to 38u when it is a legacy foo
if params[:is_legacy] == true
#foo.update_attribute(foo_type_id, 2)
end
I think there are a couple of mistakes in the following code:
if #foo.save_standard and ! row.nil?
#set foo type to 38u when it is a legacy foo
if params[:is_legacy] == true
#foo.update_attribute(foo_type_id, 2)
end
end
Try:
if #foo.save_standard && row
if params[:foo][:is_legacy]
#foo.update_attribute(:foo_type_id, 2) # careful, this method do not fire callbacks
end
end
Assuming your instance object is a Foo class (which is probably not). If not, replace
params[:foo]
by whatever your instance class is.
Related
I am trying use gem 'best_in_place' in table edit, but having error while using it
in controller only index method for display all users details from db.
Error: undefined method name' for "Rohit":String`
Code used:
<% #user_record.each do |record| %>
<tr>
<td><%= best_in_place record.name, :name %></td>
</tr>
<% end %>
controller Code:
def index
#user_record = MUser.search(params[:name],params[:gender])
end
def create
end
as I see from the docs the first argument you pass to the method best_in_place should be an object record and the second - a field you need to edit with this gem, in your case it is name.
So it will get provided field name from the record.
And since you've called name by yourself, it returns the actual value of the name instead of the whole object record and then tries to get name from that value which results in this error.
So you need to change that line to <td><%= best_in_place record, :name %></td>.
My rails application only reads data on it's database. There's no save.
Mostly all my views are a form with a few fields to filter my search and a table printing every column's value. Something like that:
<table>
<tr>
<th> Col1 </th>
<th> Col2 </th>
<th> Col3 </th>
...
</tr>
<% Model.all.each do |model| %>
<tr>
<td> <%= model.col1 %> </td>
<td> <%= model.col2 %> </td>
<td> <%= model.col3 %> </td>
...
</tr>
<% end %>
There's over 50 models each with 10-20 fields, almost 100 tables. It's all very straightforward.
Now my client asked me that when any cell is empty (the data is null or '') he wants it to print '-' instead of the blank cell on the table
At first I thought about something like this on my application_helper.rb:
def avoid_empty(object)
if object == nil or object == ""
return "-"
else
return object
end
end
and everywhere on my views I would just change
<%= model.col1 %>
to
<%= avoid_empty(model.col1) %>
but I actually have 2659 lines like that. I'm not sure it's the healthier approach.
Is there any way I can change it everytime I try to print any value from those models that I could go through that method or something similar first, without having to change every single one of my 2659 lines?
You can use the power of ruby's meta-programming and ActiveSupport::Concern.
Create a model extension module to overwrite the getter of all columns dynamically. Below code can do that:
module ModelExtension
extend ActiveSupport::Concern
# To exclude some columns
EXCLUDE_COLUMNS = ['id', 'created_at', 'updated_at']
included do
(self.column_names - EXCLUDE_COLUMNS).each do |col|
define_method col do
self[col].blank? ? '-' : self[col]
end
end
end
end
Include this module in each model to get '-' instead of blank or nil. To include model, you can do:
class MyModel
include ModelExtension
end
You can monkeypatch NilClass.
class NilClass
def to_s
'-'
end
end
Everytime you invoke, say, nil.to_s, it will print '-'. If you type puts nil in the console, will print -. Try the following example:
class NilClass
def to_s
'-'
end
end
foo = nil
foo.to_s #=> '-'
puts foo #=> -
In your case, all occurrences of empty (nil) attributes will output - in the view when trying to print (and, be warned, in other parts of your application too).
PS.: #to_s returns a string representing the instance object.
A solution maybe
The Null Object Pattern
Null Object is an object with some default behavior that implements the same interface as an other object that might be used in a given case. Ok, cool, but how can we apply it to the example below? Let's start with the user method:
def user
#user ||= User.find_by(email: email) || NullUser.new
end
And now we can implement NullUser:
class NullUser
def name
"Anonymous user"
end
end
I need to do a specific form with a parameter that is not associated to the Model that im using. See, i have in my controller (and i can reference them in my view) a specific "Order" and an array of "Products".
#this controller responds to mydomain.com/new/order/:id_order
class MyController < ApplicationController
...
def my_page
#order = Order.find(params[:id_order])
#products = Product.all
end
...
end
In my view i need to render a list with all the products with their attributes (name, description, price), a small number field next to each product and a link to "Add" the product.
I can do the table to show every attribute in each individual product of my products array, problem is, i dont know how to create a number field next to each row in my table and a link to the "Add" action, which is just a point in my API, mydomain.com/add/product/:id_order/:id_product/:amount (alias as add_product_order)
:id_order correspond to the id of the order, which i have (#order.id)
:id_product correspond to the id of the specific product of the row, which i have (product.id)
:amount must be the amount specified by the user, but i have no idea how to reference it inside the view.
The rails helper form_for, form_tag etc ... requires the url to send the data however i cant use add_product_order_path because i would need the :amount parameter so it gives me an error (but if i use a constant amount like 1, it works).
In conclusion:
<% #products.each do |product| %>
<tr>
<td><%= product.name %></td>
<td><%= product.description %></td>
<td><%= product.price %></td>
<td><input type="number" name="amount" min="1"></td>
<td><%= link_to 'Add', add_product_order_path(id_order: #order.id, id_product: product.id, amount: *???* ), method: :post %></td>
</tr>
<% end %>
What would need to be in the ??? to send the value of the amount field to the add_product_order_path?
So, the amount value its an input with an unknown value. I highly recommend that use some JS to achieve this. Something like:
$('table td a').on('click', function(e) {
var amountVal = $(this).parent('tr').find('input').val();
var newUrl = location.href.replace("amount=", "amount="+amountVal);
$(this).attr('href', newUrl);
});
I hope it helps.
UPDATE
Sorry, did'nt saw that you're using method: :post, this generates a hidden form, you have to change the hidden input value. Its posible with javascript too:
$('table td a').on('click', function(e) {
var amountVal = $(this).parent('tr').find('input').val();
$(this).parent().find('input[name*="amount"]').val(amountVal);
});
I have a show page where I need to both show the student's units and create a unit for them. However an error is being incurred when trying to do both.
In my controller
def show
#student = Student.find(params[:id])
#unit = #student.units.build
#units = #student.units
end
In my view
<%= simple_form_for #unit, url: student_units_path(#student) %>
# form...
<% end %>
<% #units.each do |unit| %>
<tr>
<td><%= unit.course %></td>
<td><%= unit.mailing_date.strftime('%m/%d/%y') %></td>
</tr>
<% end %>
The unit.course call works and any call that is only the first child of unit, however when I call a second method on unit I get this error:
undefined method `strftime' for nil:NilClass
despite knowing that the unit exists, hence the first call working
It seems your issue is that unit.mailing_date is nil, for newly-built records.
One solution would be to define a default value for mailing_date, either at the database level or in your application. For example, you could do something like:
class Unit < ActiveRecord::Base
# ....
after_initialize :set_default_mailing_date
private
def set_default_mailing_date
self.mailing_date ||= Date.today
end
end
Or alternatively, you could leave the mailing_date as nil and handle this gracefully in the view:
<td><%= unit.mailing_date.try!(:strftime, '%m/%d/%y') %></td>
If you are using ruby version 2.3+, then I would advise using the built-in safe navigation operator, rather than ActiveSupport's try! method:
<td><%= unit.mailing_date&.strftime('%m/%d/%y') %></td>
Finally, if you went with the above choice to leave the mailing_date as nil, then perhaps you'd like to display some default value in its place - for example:
<td><%= unit.mailing_date&.strftime('%m/%d/%y') || 'Not set' %></td>
As an alternative, I assume you don't want the new unit bound to the form being rendered which is what is causing the error.
You could do
#units = #student.units.reject(&:new_record?)
To remove the newly built unit from the collection
Rails 2.3.5
I have a view displaying 'employee' records in a table where each table row haas a check_box_tag to select that (row) employee record (the table is inside a form_tag). The checkbox is passing an array of employee numbers to a method but I also need it to pass some of the other information from the record (first_name, last_name, etc) in the params.
Orignally this looked like (just passing an param with an array of employee numbers)
<% #employee_search.each do |e| %>
<td><%= check_box_tag 'selected_subordinates[]', e.employee_number %></td>
<td><%= e.employee_number %></td>
<td><%= e.first_name %></td>
<td><%= e.last_name %></td>
...
<% end %>
I'm not sure this was right, but I thought I should pass the entire record ('e') in the param:
<% #employee_search.each do |e %>
<td><%= check_box_tag 'selected_subordinates[]', e %></td>
<td><%= e.employee_number %></td>
<td><%= e.first_name %></td>
<td><%= e.last_name %></td>
...
<% end %>
The param array now looks like:
"selected_subordinates"=>["#<Employee:0xa946970>", "#<Employee:0xa946910>", "#<Employee:0xa9468b0>"]
I thought at this point I would be fine and just itterate through the objects in the param array referring to the record fields, but got an undefined method error:
params[:selected_subordinates].each do |s|
puts s.last_name
end
undefined method `last_name' for "#<Employee:0xa946970>":String
I started wondering if for some reason the entire model object was passed instead of just one record from the object. But, trying [0].last_name resulted in a different error.
params[:selected_subordinates].each do |s|
puts s.last_name
end
undefined method `last_name' for 35:Fixnum
Maybe I should have been using the fields I need to build an array for the param - so the param would be an array of arrays? I haven't had any luck so far trying to search for example of what to do when you need to setup a param array made of arrays, or pass a single model object record (and refer to it).
Thank You - Much Appreciated!
When you used e as the param, Rails was converting e to a String and passing that (you can't pass an object in an HTML form, right? Just values). When you saw "#<Employee:0xa946970>" in your params hash, it wasn't an Employee object, but instead a String with the contents of #<Employee:0xa946970> (which is what you get if you called .to_s on an Employee object).
Passing the ID gets you on the right track, but once you have the ID, you should look up the Employee with that ID from the database.
params[:selected_subordinates].each do |s|
employee = Employee.find(s)
puts employee.last_name
end
Of course, this loads them one at a time, so if you have a lot of checkboxes you could end up generating a large number of queries. You can also use the find method to find multiple objects based on an array of IDs:
employees = Employee.find(params[:selected_subordinates])
employees.each do |e|
puts e.last_name
end