grouped_collection_select with different option_key_methods - ruby-on-rails

I'm using grouped_collection_select with polymorphic associations to assign either a company or person to a task. The issue is that people have a first name and a last name, while a company just has a name. I would like to use a concatenation of :fname and lname as the option_key_method for the person group in the menu and I would like to use :name as the option_key_method for the company group in the menu.
I however haven't run across this in my Google investigation. As it stands, I'm using :email as the option_key_method because it's the most distinguishing field that's shared by the two models:
<%= f.grouped_collection_select :entity_id, [Company, Person], :all, :model_name, :to_global_id, :email %>
How might I set it up to make use of the two different kinds of name fields that are implemented by the two different models?

You can pass a lambda method to the option_key_method, which takes the object currently in hand Person or Group in your case and you can do the processing you want on it
Example:
<%= f.grouped_collection_select :entity_id, [Company, Person], :all, :model_name, :to_global_id, lambda {|company_or_person_object| company_or_person_object.instance_of? Company ? company_or_person_object.fname + company_or_person_object.lname : company_or_person_object.name} %>

Related

Simple Form - Multiple attributes in checkbox group

I have a User Model with the following attributes:
# full_time :boolean
# part_time :boolean
# contract :boolean
I would like to create a simple form checkboxes group for these attributes. From what I've been able to understand, the simple form api is meant to map to has_many & has_and_belongs_to_many associations, as follows:
f.collection_check_boxes :role_ids, Role.all, :id, :name
Is there a way to handle updating multiple attributes on the given model within the form's API guidelines? Or is this an indication that should I be modeling the data in a different way?
f.collection_check_boxes is a generic method for generating multiple checkboxes with arbitrary name/value, for a single attribute. The sample you gave is mentioned in the docs as a last one for this method, probably because f.association is way better for association attributes.
<%= f.association :role, Role.all %>
In case of your attributes, I don't think f.collection_check_boxes is applicable. If the attributes aren't mutually exclusive, then I don't see anything wrong - stick with them and just give each one a checkbox of it's own.
<%= f.input :full_time %>
<%= f.input :part_time %>
<%= f.input :contract %>
simple_form will detect their type and generate a checkbox for each. Use wrapper: false option, if you want to get rid of wrapper divs and group them more tightly.
If they were mutually exlusive, then an integer column and enum would be probably a better idea.

Rails collection_check_boxes, Using two labels with one from an association

I have an Available model with a date attribute, I also have a User model. A user has_many :availables and available belongs_to :user.
#dates is a collection of Available records. In the form I want to show both the date and the associated user name for that record. What I currently have is working though I can't click name to select the checkbox, is there a proper way to do this and style it via bootstrap?
= f.collection_check_boxes :col_ids, #dates, :id, :date do |b|
.field
.checkbox-inline
= b.check_box
= b.label
= b.object.user.name
What you want is a checkbox which is inside the label tag.
= f.collection_check_boxes :col_ids, #dates, :id, :date do |b|
.field
.checkbox-inline
= b.label do
= b.check_box
= b.text
= b.object.user.name
On a side note your model should be named Availablity which is a noun. Not the adverb form available (availables is not an english word).
A person may be available, but has many availabilities.
availability
plural avail·abil·i·ties
the quality or state of being available
an available person or
thing
http://www.merriam-webster.com/dictionary/availability
This is not a big deal but can give english speakers are real WTF moment when trying to understand your code.

Money Rails Gem - null values

I have monetised two models of my Rails 4 app with Money-Rails gem.
One is called Participants, the other is called Funding. Each of these models is nested inside another model, called Scope. Scope belongs to Project.
The associations are:
Project has one Scope; Scope belongs to Project
Scope has one Participant and has one funding; each of Participant and Funding belong to Scope.
Project accepts nested attributes for Scope. Scope accepts nested attributes for Participant and Funding.
Params for each relevant attribute in Participant and Funding are permitted in the Scope and Project Controllers as well as the models themselves. Params for Scope are permitted in the Scope and Project controllers.
In my Project form, I ask several questions. That form also has nested forms for each of the models which belong to it. Inside the Scope form, I ask users two boolean questions, being: Do you want participants? Do you want funding? Each of these models has a follow up question about participation cost and funding (those attributes are monetised).
If the answer to those questions is true, then I reveal the participant or funding form partial and ask how much money they want.
I have two problems:
First problem: Not null violation
1. If a user says they do want participants, but there is no associated costs, so that the boolean question inside the participant model asking whether there is cost involved with participation, I get an error that says:
ERROR: null value in column "participation_cost_pennies" violates not-null constraint
If a user says they don't want participants in answer to the question asked in the Scope form, I get the same error as in 1 above
Second problem: If I save an amount in the monetised fields, and come back to edit the project form, the form does not show the saved amount in the monetised field - and if you don't reenter it, I get an error saying that it can't be blank.
Does anyone know how to:
make the first problem go away in all circumstances except those when participation costs are actually sought; and
Fix the second problem by displaying the original amount saved when you come back to edit the form? I have tried inserting :selected into my form element, but it doesn't do anything.
My code is as follows:
Inside my Scope form (nested inside my project form):
<%= f.simple_fields_for :scope do |s_all| %>
<%= s_all.input :if_participant, :as => :boolean, :label => false, inline_label: 'Public participants or volunteers' %>
<%= s_all.input :if_funding, :as => :boolean, :label => false, inline_label: 'Funding or expenses' %>
If the answer to these fields is true, then I reveal the partial forms for participant of funding (for whichever is true).
Inside my Participants partial form, I have:
<%= f.simple_fields_for :scope do |participants_s| %>
<%= participants_s.simple_fields_for :participant do |par| %>
<%= f.label 'Are participants reimbursed for their costs?', :class => 'question-project' %>
<%= par.collection_radio_buttons :costs, [[true, ' Yes'], [false, ' No']], :first, :last, {:item_wrapper_class => 'fixradio'}, {:class => "response-project"} %>
<%= f.label 'What amount will you pay for participation costs?', :class => 'question-project' %>
<%= par.select :participation_cost_currency,
options_for_select(major_currencies(Money::Currency.table)), selected: :participation_cost_currency,
label: false,
prompt: "Select your costs currency" %>
<%= par.input :participation_cost, label: false, placeholder: 'Whole numbers only', selected: :participation_cost_pennies, :input_html => {:style => 'width: 250px; margin-top: 20px', class: 'response-project'} %>
For the first problem, you'll want to set a default value for the participation_cost_cents column in a migration:
# in console
> rails g migration change_default_for_participation_cost_cents
# in migration file
class ChangeDefaultForParticipationCostCents < ActiveRecord::Migration
def change
change_column :participants, :participation_cost_cents, :integer, default: 0
end
end
I'm not sure I follow on the second problem though. Maybe you should split the question in two?
A meetup group for Rails has helped me answer this question. The answer is not obvious - especially for newcomers.
My problem was I had an attribute in my database called participation_cost. Monetise then tried to make a method with the same name and that was failing because of the attribute in my table. For others, you don't need the attribute in your database with the name of the field you want to monetise.
Removing that attribute (in my case, participation_cost) solved my problem.

ruby on rails how to use FormOptionHelpers to create dynamic drop down list

I have checked some tutorials but I got confused by the parameters in this method
collection_select (object, attribute, collection, value_method, text_method, options = {}, html_options ={})
I have a map model includes: :area, :system, :file
and I want to read :area from database to a drop down list, and let user choose one
I already did #map = Map.all in the view
what the method should be?
especially the parameter "attribute". In a lot tutorials, people put "id" here. But I don't know what "id" is, and in my situation I don't need any other value, just the "area".
Im not exactly sure what you are asking here but if you are trying to make a dropdown selection for use in an html form will this example help you at all?
<% nations = {'United States of America' => 'USA', 'Canada' => 'Canada', 'Mexico' => 'Mexico', 'United Kingdom'=> 'UK'} %>
<% list = nations.sort %>
<%= f.select :country, list, %>
Here nations is a hash of countries then list becomes the sorted copy of that hash. An html dropdown is then created as a part of the form "f". ":country" is the part of the model that the data is connected to while list is the options to populate the dropdown with
It's not clear from your question what the model is that's being populated with the area.
Typically, collection_select is used between related models.
eg.
class Category < ActiveRecord::Base
has_many :products
end
class Product < ActiveRecord::Base
belongs_to :category
end
When selecting the 'category' for a product, your view would have something like:
<%= f.collection_select(:category_id, :id, Category.all, :name, include_blank: true) %>
What this does is specify the Product.category_id as the attribute being populated with the value of Category.id. The values come from the Category.all collection, and with Category.name being the item displayed in the select. The last (optional) parameter says to include a blank entry.
Something like the following is probably what you need:
<%= f.collection_select(:map_id, :id, #map, :area) %>
However, if the model you're trying to populate has an area attribute (instead of an ID linking to the map), you might need to use:
<%= f.collection_select(:area, :area, #map, :area) %>
This specifies that the area attribute of the receiving table will be populated with Map's area attribute, which is also being used as the "description" in the select.

In Rails 3 how should I manage a model column with limited choices

In my Rails 3 application I have numerous models that have columns that have limited choices (IE a select box). It seems overkill in these cases to create another model and a relationship to the original model just to manage the choices.
One option I can think of is to just create a select box and have the choices in there, but that doesn't seem very DRY. Does anyone have a good suggestion how to handle this situation?
Thanks for looking.
You could create a constant in your model like so
# formatted as an array of options, option being an array of key, value
OPTIONS = [['Email', 'email'], ['Text', 'text'], ['Email and Text', 'both']]
validates_inclusion_of :field, :in => OPTIONS
Which can then be used to populate a select menu in a view very easily
Example using formtastic
<%= f.input :field, :as => :select, :collection => Model::OPTIONS %>
I usually do this with a constant list in the model.
class Model < ActiveRecord::Base
PROPERTY_OPTIONS = ['Option One', 'Option Two', ...]
validates_inclusion_of :property, :in => PROPERTY_OPTIONS
end
And in the view:
<%= f.select :property, Model::PROPERTY_OPTIONS %>
You can also use the enum_column plugin: https://github.com/electronick/enum_column
You can then render your select boxes in your views as follows:
<%= f.select :status, Model.columns_hash['status'].limit %>
(Where Model is an example model name, such as Book or Product, or whatever it is your application is really about.)
In some cases, I will just create a hash of options and use Class Methods to display and set them. For example, a Problem model with different statuses could be done like so:
def self.statuses
{:open => 1, :closed => 2}
end
Then you just store the integer value in the status_id of the model. You can configure getters/setters as well.

Resources