Rails: Optional lookup fields - ruby-on-rails

In my Rails app I am using collection_select to provide a list of valid choices for the user. I stored only the id from the looked-up table. I then make a call to the looked-up class in the show view to retrieve the actual value for the id.
in edit:
= f.collection_select :language_id, Language.find(:all, :conditions => ["supported = 't'"]), :id, :language, include_blank: false, :prompt => "Language"
in show:
%p
%b Language:
= Language.find(#article.language_id).language_code
This is all working fine unless no choice is made. If the #article.language_id field is null, the view cannot load as the find fails. Any suggestions on how to ignore null values and leave the field blank?

using find_by_id would be an option, as it does not raise an error if the id could not be found.
this issues a call to the database though.
so i would just check the languange_id and provide a default
= #article.language_id.nil? ? default : Language.find_by_id(#article.language_id)
this could also be moved into the model or a helper, so that it does not clutter your view code.

This is a common problem. Simply use try to leave nil values:
if #article.try(:language_id) != nil
#code = Language.find(#article.language_id).language_code
else
//default nil
#code = nil
end

Related

Rails Simple Form Default Value if Submitted Nil

I need to overwrite any blank field submissions in my simple form with the text value "N/A". I've found how to set a default value beforehand, but I would like the field left blank for users to fill out and submit, and only changed if they leave it blank. Is this possible? Thanks!
<%= f.input :survey_year, :input_html => { :value => 'N/A'} %>
Should do the trick. See the flipflops.org link in my comment above for alternative approaches.
Try to the following
before_save :default_values
def default_values
self.name ||= 'N/A' #=> note self.name = 'N/A' if self.name.nil?
end
When a user submits a form with blank/nil name then it will submit to "N/A" otherwise none

How do I use a check_box_tag for value that isn't a boolean?

I have a field in my database called property_types which has a string value and the values can be "Condo" or "Single Family Home" or "Commercial". I want to display each property type in the user's search form with a check box next to each property type so the user can select which property types should be included in their search results.
But if the property_type field is not a boolean and it has several possible values how do I do this using check_box_tag which can only have a true or false value?
EDIT:
I added this checkbox code to properties/index where the search form is and the search results are displayed:
<%= check_box_tag(:condo, value = "1", checked = true) %>
In properties_controller I added this:
#properties = #properties.where(:property_type => "Condo") if params[:condo].present?
Ofcourse it doesn't work because I haven't got a clue what I'm doing but is this along the right lines or not?
Well, looking at you requirements i would suggest you to leave the values at true and false, and on your controller, when you persist the object, you check all possibilities that are checked (true) and put you project_types attribute together.
project_types += 'condo&' if params[:condo]
project_types += 'commercial&' if params[:commercial]
...
Of course the & i put in the examples are just for demonstration, as i don't know how you would create this string.
EDIT:
Well, maybe you should refactor your model. I believe it would be easier if the project_types attribute didn't exist, and instead, you had several boolean attributes named after your strings. Then you can search like this:
#properties.where(:condo => params[:condo], :commercial => params[:commercial])
And it would be easier to understand the code.

Array as Parameter from Rails Select Helper

I'm working on a legacy project that is using acts_as_taggable_on which expects tags to come in arrays. I have a select box allowing users to select a tag on a Course in a field called categories. The only way mass assignment create will work is if params looks like this params = {:course => {:categories => ['Presentation']}}. I've currently a view with this helper:
<%= f.select 'categories', ['Presentation' , 'Round Table' , 'Demo', 'Hands-on'] %>
Which will give me a parameter like params = {:course => {:categories => 'Presentation'}}. This doesn't work since Acts as tag gable apparently can't handle being passed anything other than a collection.
I've tried changing categories to categories[] but then I get this error:
undefined method `categories[]' for #<Course:0x007f9d95c5b810>
Does anyone know the correct way to format my select tag to return an array to the controller? I'm using Rails 3.2.3
I didn't work with acts_as_taggable_on, but maybe this simple hack will be suitable for you? You should put it before mass-assignment.
category = params[:course][:categories]
params[:course][:categories] = [category]
If you are only going to allow the selection of ONE tag, you could do:
<%= f.select 'categories', [['Presentation'] , ['Round Table'] , ['Demo'], ['Hands-on']] %>
Each one item array will have first for the display value, and last for the return value, which in this case will both return the same thing, as the first element of the array is the same as the last element when the array as one element.
Seems like select doesn't give you that option.
If I understand correctly, one option might be to use a select_tag instead and just be explicit about where you want the selection in the params:
<%= select_tag 'course[categories][]', options_for_select(['Presentation' , 'Round Table' , 'Demo', 'Hands-on']) %>
That ought to get your params the way you need them.
Here's what I'm using for one of my projects:
<% options = { include_blank: true } %>
<% html_options = { required: true, name: "#{f.object_name}[#{resource.id}][days][]" } %>
<%= f.select :days, DAYS, options, html_options %>
Without html_options[:name], Rails handles the name of the select tag and spits out something like
service[service_add_ons_attributes][11][days]
but I need
service[service_add_ons_attributes][11][days][]
So I override it.
Hope that helps.

Rails Select boolean with NULL value

First the environment:
Rails 2.1.0, Ruby 1.8.7, Mysql 5.1.54, Ubuntu 11.04
I have a boolean field in my table which starts as NULL, but I can not find a good way to set it to NULL. (This field is basically a yes / no / unanswered field, which true / false / null seems about right for. The client specifically said he would like it to be able to remain null (unanswered).)
Here is my migration (specific names replaced):
class AddQuestionToClients < ActiveRecord::Migration
def self.up
add_column :clients, :question, :boolean
end
def self.down
remove_column :clients, :question
end
end
My controller uses a basic
#client = Client.find(params[:id])
#client.update_attributes(params[:client])
My view has a select (I think this is causing the problem, was never great with form helper selects):
<%= f.select :question, [["Yes", true], ["No", false]], { :include_blank => true, :selected => #client.question } %>
When selecting yes, true is passed; no, false is passed; blank, "" is passed.
But "" seems to automatically convert to false when updating the database.
To get around this, I'm doing this:
params[:client][:question] = (params[:client][:question] == "")? nil : params[:client][:question]
But this can't be the right way to do it. What am I missing?
I just ran into the same problem, and I solved it by making the attribute convert blank to null. In your case, I would add a method to your model class.
class Client < ActiveRecord::Base
def question=(value)
value = nil if value == ''
super(value)
end
end
This works for both create and update. (I'm using Rails 2.0.5.)
I think that you can do that only in that way server side, because when a data is posted is always not nil. So your solution is correct.
If you want to avoid that ugly code you can do a little trick client side using javascript. In fact if you use a disabled element instead of a blank value that value won't be posted and you get nil on server side.
To do that you can add a submit callback that checks whether the question field is blank and if so disable it before posting data. In that way it will work without any server side code.
To disable an element using jQuery you can see this link. So assuming your form has the #form id you can use this code
$(function() {
$('#form').submit(function () {
if ($('question-selector').val() == "") {
$('question-selector').attr('disabled', true);
}
})
});
I had the same problem, i needed null value by default for boolean to represent "not answered"
With Rails 3.2, when i pass "" for a boolean value (blank option) is sets the column to NULL in db.
So problem solved with newer version of rails :)
<%= f.select :question, options_for_select([["Yes", true], ["No", false]], :question) %>
#vdaubry I would only add that it is not really solved ..it is masked because you are using 'select' in your UI. If you are foolish enough to use checkboxes, like me (after all, they are booleans, right?) then your nice default nil value in the db, which we mean to represent 'unknown' is converted to 'false' when rendered in the view, and converted to false in the db, even when it is not updated in the view, same as was described above. In other words, it's a bit brittle to continue to rely on a 3rd value for 'boolean' being consistent.
Furthermore, if ever reporting on this attribute, your reporting code cannot easily deduce the values in the db, if "unknown" is a valid meaning and is obscured.
So I chose to refactor all my booleans making them strings ('yes', 'no', 'unknown') and use radio buttons in the views. Note this only matters for things like data collection UIs, where a user has not got round to finding out the truth, so statistically it matters a lot if it's "unknown".
This isn't mentioned in previous posts, but in Rails 5 this should work if you want to name the nil option
<%= f.select :question, [["Yes", true], ["No", false]], { :include_blank => 'Name this whatever you want, it will be nil when submitted', :selected => #client.question } %>
Tested this on my own project

String concatenation not possible?

So over the last 2 hours, I've been trying to fill a combobox with all my users. I managed to get all firstnames in a combobox, but I want their full name in the combobox. No problem you would think, just concatenate the names and you're done. + and << should be the concatenation operator to do this.So this is my code:
<%= collection_select(:user, :user_id, #users, :user_id, :user_firstname + :user_lastname, {:prompt => false}) %>
But it seems RoR doesn't accept this:
undefined method `+' for :user_firstname:Symbol
What am I doing wrong?
What you need to do is define a method on the User model that does this concatenation for you. Symbols can't be concatenated. So to your user model, add this function:
def name
"#{self.first_name} #{self.last_name}"
end
then change the code in the view to this:
<%= collection_select(:user, :user_id, #users, :user_id, :name, {:prompt => false}) %>
Should do the trick.
This isn't really rails giving you an error, it's ruby. You're trying to combine the symbols :user_firstname and :user_lastname
A symbol is a variable type, just like integer, string, or datetime (Well technically they're classes, but in this context we can think of them as variable types). They look similar to strings, and can function similarly to them, but there is no definition for the behavior of symbol concatenation. Essentially you're trying to send the method user_firstnameuser_lastname which is just as non-sensical as trying to concat two Symbols.
What you need to understand is that this parameter is looking for a method on your User object, and it won't understand the combination of two symbols. You need to define a method in your model:
def fullname
[user_firstname, user_lastname].reject{|v| v.blank?}.join(" ")
end
This'll return your first + last name for you, and then in the parameter you should send :fullname (because that's the method it'll call on each user object in the collection):
<%= collection_select(:user, :user_id, #users, :user_id, :fullname, {:prompt => false})%>
Also, it's considered poor practice to prefix every single column with the table name. user.user_firstname just looks redundant. I prefer to drop that prefix, but I guess it's mostly up to personal preference.
The arguments for value and display attribute are method names, not expressions on a user object.
To control the format more precisely, you can use the select tag helper instead:
select("user", "user_id", #users.each {|u| [ "#{u.first_name u.last_name}", u.user_id ] })
The docs are pretty useful.

Resources