Money Rails Gem - null values - ruby-on-rails

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.

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 Simple Form Select from Array - polymorphic associations

I am making an app in Rails 4. I use Simple Form for forms.
I have a profile model and an organisation model.
The associations are:
profile.rb
has_one :organisation, as: :orgable
organisation.rb
has_many :profiles
In my organisation table, I have an attribute called :org_type.
In my organisation form, I ask users to select from an array of types of organisation:
<%= f.input :org_type, :label => "Organisation type", collection: [ "University", "Research Organisation", "Company"] %>
In my profile form, I want to ask users which uni they study at.
I want to use the array of universities created within the organisation model.
I have a scope in my organisation model to filter out the universities:
scope :all_uni, -> { where(org_type: 'University') }
In my profile form I have:
<%= f.input :institution, :label => "Graduated from" %>
But this just has a text field.
I have tried to replace that line with an attempt at making a select function in my form which refers to my organisation model scope for all_uni. It looks like this:
<%= f.select(:institution, #organisation.all_uni.title.map { |value| [ value, value ] }) %>
It gives this error:
undefined method `all_uni' for nil:NilClass
I don't understand what this error message means, but I'm also not sure I'm on the right track with the form select field either. Any tips for where to look to get this working. I'm not sure how to go about setting up the select field in the first place?
ANOTHER ATTEMPT:
I have also tried using this in my profile form:
<%= f.select(:institution, #organisation.all_uni.title) %>
But I get the same error. I must be way off track - i've exhausted every option I can find.
ANOTHER ATTEMPT
I found this post
Rails Simple Form custom association select field
Taking the example in that solution, I tried:
<%= f.input :institution do %>
<%= f.select :institution, Profile.Organisation.all_uni.map{ |l| [l.title {:title => l.title.titlecase}] } %>
<% end %>
But, I get this syntax error. I've tried removing the => but keep getting more syntax errors.
syntax error, unexpected =>, expecting '}' ...i.map{ |l| [l.title {:title => l.title.titlecase}] } );#out... ... ^
Not a complete answer but according to what I know is, If you got 2 models then instead of using
profile.rb
has_one :organisation, as: :orgable
organisation.rb
has_many :profiles
You can simply use
profile.rb
belongs_to :organisation
organisation.rb
has_many :profiles

Limiting down the amount of calls to the database during a simple_form with multiple HABTM

I am currently trying to speed up an old (3.2) Rails app and hitting an issue with way too many calls being made to the database during an edit view using simple_form
Here is the simplified setup;
class Event
HABTM Speakers
HABTM Sponsors
class Speaker
belongs_to Sponsor
HABTM Events
class Sponsor
have_many Speakers
HABTM Events
For an event we want to show both each potential speaker (of which there are thousands) and all the sponsors (hundreds).
For each speaker if they have a sponsor they need to show the sponsor name.
This all adds up to a lot of calls to the sponsors table, way too many.
Current Code
Right now the simple_form is set up as;
<%= simple_form_for [:admin, #event] do |f| %>
...
<%= f.association :speakers, :input_html => { :class => 'select2able' }, :label_method => :summary %>
...
<%= f.association :sponsors, :input_html => { :class => 'select2able' } %>
...
That label method is on the speaker model;
delegate :name, to: :sponsor, prefix: true, allow_nil: true
def summary
[name, job_title, sponsor_name].compact.join ' - '
end
The #event variable is assigned in the controller with a simple
#event = Event.find params['id']
This is where I have been spending most of my time trying to improve.
What I have tried
Calling Event.includes(:speakers => :sponsor).find() I thought would help. but it hasn't at all.
I have also tried just including speaker and sponsor separately.
I have searched around for people having issues with simple_form specifically but haven't found anything. I know this is a sign of the mental structure that was made, but anything I can do to improve it without a complete re-write would be excellent.
I was almost there with my original attempts.
This version of Rails didn't like the external includes (it executed but didn't apply anything)
The final code was a slight change where I brought the include inside the find_by.
Event.find_by_slug(params[:id], :include => [:speakers, :sponsors, :speakers => :sponsor])

Ruby on Rails: Nested Model Form Checkbox For A 'has_many :through' Relationship

Still fairly new to RoR, let alone Ruby itself.
Here's my issue. I'm using Rails 4 and Ruby 2.1.0
I have a User class with this relationship:
has_many :roles, ->{ uniq }, :through => :user_roles
accepts_nested_attributes_for :roles
Now, the table 'roles' simply has a list of roles, such as 'admin', 'moderator', 'visitor', 'artist', etc.
The table 'user_roles', is just a relational table, with the role's key and the user's key.
So, to clarify, 'users' has a one to many relationship with 'user_roles' and "user_roles' table has a many to one relationship with the 'roles' table.
Something like this:
users: id, name, email #ie: 12, 'mikey', 'mike#foobar.com'
user_roles: id, user_id, role_id #ie: 4324, 12, 8
roles: id, name, weight #ie: 8, 'moderator', 11
I've been given the task of adding a checkbox toggle in the admin section so that an admin can grant the moderator role to any one user.
Each admin page is for one specific user. Therefore, the form_for is based on the #user instance, depending on which user the admin selected for editing.
RailsCasts #196 kind of helped me understand the concept, but it's platform is just different enough that I'm not sure how to exactly translate it into what I need. Likewise, there are some similar questions here on StackOverflow as well - but again, I can't seem to get it to translate correctly into my situation.
What I do have, I think should be at least somewhere in the realm of the right direction. THen again, maybe I'm way off. Here is my form code:
= form_for #user, :url => admin_user_path(#user), html:{class: 'form_horizontal'} do |f|
%br
%h4{class: :dc_green}Logistical Information
= f.label :display_name, "Display Name"
= f.text_field :display_name
= f.label :email, "eMail"
= f.text_field :email
%br
= f.fields_for :roles do |a|
= a.check_box :moderator, { inline_label: :none }
= a.label :moderator, {for: :moderator, class: "checkbox inline"}
%br
The error I'm getting with this form code is: undefined method `moderator'
Thank you in advance for anyone who can offer support :)
I guess I should probably add that I'm also clueless as to how I should handle this in the controller once it is submitted. But, first things first.
UPDATE
So, the reason I'm getting the undefined error is because it doesn't exist for that user. Which is bad. I need to be able to add the role to the user or remove the role. However, the only roles coming through are the roles the user has already been assigned to. So I'm totally doing this wrong. Now I'm really in the dark.

Radio buttons grouped over multiple nested form entries

I'm using RoR with simple_form and cocoon to handle this structure : Node has_many :addresses
Each Address has a boolean :main field which will flag one of each Node address as the main one (actually the one used for SNMP monitoring).
I've a nested form to manage these addresses but I can't find a clean way to select the main one.
Logically, I should use a radio buttons group, each address being one radio group option, but, in a nested form, each radio button will belong to one single address and have a different name, meaning they're in different groups.
I could link the radio button input to a virtual attribute in Node, and set selected address':main field to true in a callback, but how will I link each button to its address (I could use address ID as button value, but newly added addresses have no ID yet).
Here's a simplified version of what my Node form should look like (parentheses represent radio buttons, brackets for text inputs) :
Name : [MyNode1 ]
| Address | Main |
|------------|------|
| [10.0.0.1] | (*) |
| [10.0.0.2] | ( ) |
| [10.0.0.3] | ( ) |
My only other solution would be a JS feeded selectbox (options updated when I change something in addresses list) but it's definitely less clean and logical than a simple radio group...
Edit
An "acceptable" workaround would be to group radio buttons on something else than name attribute (example : data-group attribute). Does someone know any good JS/jQuery plug-in that could do this ?
I had a similar problem, with a Title that had many Role objects (a HMT glue model, which said which Person had done what to that title -- author, editor, translator, whatever). Each title had a primary person, usually the author, but sometimes an editor or curator, as in an encyclopedia. Try as I might, I could not get Rails to use a radio button in a newly created nested model, as you have seen. Here's what I ended up doing:
In the nested Role partial:
<p>
<%= f.collection_select :name, person_roles, :to_s, :titleize, {:prompt => "Role"}, {:class => 'combo'} %>
<%= f.collection_select :person_id, Person.order(:sort_name), :id, :reverse_name, :prompt => "Person" %>
<%- if ! f.object.new_record? -%>
<%= radio_button_tag 'title[role_id]', f.object.id, (#title.role_id == f.object.id) %>
<%= label_tag :role_id, "Primary", :for => "title_role_id_#{f.object.id}" %>
<%- end -%>
<%- if ! f.object.new_record? -%>
<%= f.link_to_remove "Delete", :class => 'delete' %>
<%- end -%>
In the Title model:
has_many :roles, :dependent => :destroy
has_many :people, :through => :roles
belongs_to :role #the primary person, like the author or editor
accepts_nested_attributes_for :roles, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
after_create :set_primary
def set_primary
self.update_attributes( :role_id => self.roles.first.id ) if self.roles && self.roles.first
end
So the radio buttons don't even appear unless the nested models have been saved. Adding a new nested model will give you a form partial missing the radio button and delete link (since neither would work until that nested child had been saved).

Resources