Php to Rails - Rails Associations - contact_to_groups table - ruby-on-rails-3

I have CRUD in place for creating contacts and creating groups. Both are nested under the user model.
I need to know how I can now associate contacts with groups.
I would like in my contact form to have some checkboxes (using formtastic) so the user can select which group(s) the contact belongs to.
In php i would make a table called contacts_to_groups and i would have contact_id & group_id columns, then when I would save the contact i would pass that data and use a join to get it back out later.
Thanks!
contact create form
<%= semantic_form_for [#contact.user, #contact] do |f| %>
<% f.inputs do %>
<%= f.input :firstname, :label => 'First Name' %>
<%= f.input :lastname, :label => 'Last Name' %>
<%= f.input :email, :label => 'Email' %>
<%= f.input :notes, :input_html => { :class => 'autogrow', :rows => 10, :cols => 50, :maxlength => 10 }, :label => 'Notes' %>
<% end %>
<%= f.buttons %>
<% end %>

Correct your models like this:
class Group < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :contacts
end
class Contact < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :groups
end
And then you need to create table in DB contacts_groups(contact_id, group_id)

Related

Rails creating a collection without an association

What is the best and correct way to setup a simple_forms_for field that contains a collection for a select field but the values to be contained in the select need to be sourced from a model that does not have a direct association to the calling fields model?
For example I have a simple_forms_for form like follows:
<%= simple_form_for(#customer) do |f| %>
<%= f.error_notification %>
<fieldset>
<div class="form-inputs">
<%= f.input :code, required: true %>
<%= f.input :name, required: true %>
<%= f.input :location, required: true %>
<%= f.input :service_level %>
<%= f.input :golive_date, :as => :date_picker %>
<%= f.input :connection_type %>
<%= f.input :service_centre %>
<%= f.input :end_date, :as => :date_picker %>
<%= f.input :sla %>
<%= f.input :project_code %>
</div>
<div class="form-actions">
<%= f.button :submit, :class => "btn btn-primary" %>
</div>
</fieldset>
<% end %>
I want to make the :service_level field a selection field and add a collection to it, however the table that stores the lookup values is not associated with the Customer table for the form.
class Lookup < ActiveRecord::Base
validates_presence_of :name, :description
has_many :lookup_values
accepts_nested_attributes_for :lookup_values, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end
class LookupValue < ActiveRecord::Base
belongs_to :lookup
end
class CreateLookups < ActiveRecord::Migration
def change
create_table :lookups do |t|
t.string :name
t.string :description
t.timestamps
end
end
end
class CreateLookupValues < ActiveRecord::Migration
def change
create_table :lookup_values do |t|
t.integer :lookup_id
t.string :name
t.string :value
t.timestamps
end
end
end
I basically want to be able to populate the values of the select using the following SQL query:
select v.name||' - '||v.value
from lookup_values v,
lookups l
where v.lookup_id = l.id
and l.name = 'Service level';
The actual value that is saved into the :service_level field needs to be the value of v.name.
All of the collections examples I have seen only appear to show how to create selects based on models that have an association between them, just wondering if there is an easy way to achieve this without an association.
Ok, well this is embarrassing...
Simple solution was to modify the _form.html.erb view file so that the :service_level field reads as:
<%= f.input :service_level, :collection => LookupValue.joins(:lookup).where(lookups: { :name => 'Service level' }).pluck(:name) %>
I probably need to make this more DRY when repeating for multiple lookup values in the form.
Any ideas how I can enhance this code to:
Remove the blank value that is listed in the select field drop down?
Modify the value text that displays in the select drop down to be
Name ||' - '||value. For example show the values in the format
"L1 - Level 1". The actual value selected and saved would need to
remain as "L1" (the :name value)

Rails nested form on HABTM: how to prevent duplicate entry?

I have simple app with 3 tables in DB and 'many-to-many' relationships.
# Model Employee
class Employee < ActiveRecord::Base
has_and_belongs_to_many :phonenumbers
accepts_nested_attributes_for :phonenumbers, :allow_destroy => true
attr_accessible :last_name, :first_name, :middle_name, :phonenumbers_attributes
end
# Model Phonenumber
class Phonenumber < ActiveRecord::Base
has_and_belongs_to_many :employees
attr_accessible :number
accepts_nested_attributes_for :employees
end
I have 'employees_phonenumbers' join-table with 'employee_id' and 'phonenumber_id' columns.
# View
<%= form_for #employee, :url => { :action => :create } do |f| %>
<%= f.label "Last name" %>
<%= f.text_field :last_name %>
<%= f.label "First name" %>
<%= f.text_field :first_name %>
<%= f.label "Middle name" %>
<%= f.text_field :middle_name %>
<%= f.fields_for :phonenumbers do |phonenumber| %>
<%= phonenumber.label "Phone number" %>
<%= phonenumber.telephone_field :number %>
<% end %>
<%= f.submit "Create" %>
<% end %>
# Controller
def create
#employee = Employee.new(params[:employee])
#employee.save ? (redirect_to :action => :index) : (render "new")
end
Now if I create a user: 'John' with phone number '555', it's OK.
But if I want to create a user 'Larry' with the same phone number '555', there's a dublicate of '555' entry in the DB.
How do I prevent this?
UPDATE: My logic is: If there is number '555', then do not create a new one, use existing. If there is no such a number, then create a new one and use it.
in employee.rb:
before_save :get_phonenumbers
def get_phonenumbers
self.phonenumbers = self.phonenumbers.collect do |phonenumber|
Phonenumber.find_or_create_by_number(phonenumber.number)
end
end
I have found its working
You can use rails validation to check uniqueness of record.
In your model phonenumber.rb put following line,
validates_uniqueness_of :column_name
It will ensure that Phonenumber will have unique phone_numbers only.
Now in controller you can check phone_number from params and if number is already exist then we will delete nested attributes fron params so that Phonenumber record wont generate.
def create
#phone_number = Phonenumber.where(:number=>params[:employee][:phonenumber][:number])
if #phone_number.any?
params[:employee].delete(:phonenumber)
#employee = Employee.new(params[:employee])
if #employee.save?
#employee.phonenumber = #phone_number.first
redirect_to :action => :index
else
render "new"
end
else
#employee = Employee.new(params[:employee])
#employee.save ? (redirect_to :action => :index) : (render "new")
end
end

Rails 3 - how to assign the value to nested attributes before calling save in update action

Models associations are
document.rb
has_many :sections
accepts_nested_attributes_for :sections, :allow_destroy => :true, :reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
section.rb
belongs_to :document
has_many :paragraphs, :dependent => :destroy
has_many :contents :through => :paragraphs
validates :user_id, :presence => { :message => "Must be filled" }
paragraph.rb
attr_accessible :user_id, :section_id, :content_id
belongs_to :section
belongs_to :content
validates :user_id, :section, :content, :presence => { :message => "Must be filled" }
paragraphs table just like a intermediate table for sections and contents and I want to save records in documents, sections and paragraphs table using single submission.
So I designed form as like
_form.html.erb
<%= form_for #document, :validate => true do |f| %>
<%= f.error_messages %>
<%= f.text_field :name %>
<% f.fields_for :sections do |builder| %>
<%= builder.text_field :name %>
<%= builder.select :content_ids .... {:multiple => true} %>
<% end %>
<% end %>
example parameters when submiting the form
{"document"=>{"name"=>"sdf", "sections_attributes"=>{"0"=>{"name"=>"sdf", "description"=>"sdf", "_destroy"=>"0", "content_ids" => ["1", "2"]}}, "commit"=>"Update Document", "id"=>"3"}
In additionally, I am updating current_user's id to user_id column of paragraphs table.
update
#document = Document.find(params[:id])
#document.attributes = params[:document]
#document.sections.each {|section|
section.user_id = current_user.id
section.paragraphs.each {|paragraph| paragraph.user_id = current_user.id}
}
if #document.save!
# success
else
render :action => 'edit'
end
I got "Validation failed: User Must be filled".
Is validation triggered when assigning attributes using object.attributes= as above
How to assign the value to user_id in paragraph object before calling save method
Might help.
<%= f.hidden_field :user_id, value: current_user.id %>

Rails: Validation for a simple_form using has_many relationship (e.g. Person, Phone)

I'm struggling getting the desired validation with nested models within a simple_form. You'll be able to see from the models below a Person can have many Phone's, the desired behaviour is to present edit fields for any existing numbers plus an additional one should for a new number, if this new number isn't filled in by the user then it's just ignore and not saved in the database. I also want to achieve similar with Email.
When landing on the /people/:id/edit page this blank field is being prematurely validated and producing visible errors on the form before submitting. It doesn't do this when visiting /people/:id/new page; I'm assuming that this is because new_record? returns true for the user model on the new page? In reading a similar post I added on: :save as a parameter to validates on the Phone model although this just allowed blank records into the database, perhaps because this isn't relevant when the user model is saving the record?
class Person < ActiveRecord::Base
belongs_to :company
has_many :phones, :as => :phoneable
has_many :emails, :as => :emailable
has_many :addresses, :as => :addressable
attr_accessible :first_name, :job_title, :last_name, :prefix, :phones_attributes, :emails_attributes, :addresses_attributes, :company_id
accepts_nested_attributes_for :phones, allow_destroy: true, reject_if: proc { |attributes| attributes['number'].blank? }
accepts_nested_attributes_for :emails, allow_destroy: true, reject_if: proc { |attributes| attributes['email'].blank? }
accepts_nested_attributes_for :addresses, allow_destroy: true, reject_if: :all_blank
validates :first_name, :last_name, presence: true
def to_s
"#{first_name} #{last_name}"
end
end
class Phone < ActiveRecord::Base
belongs_to :phoneable, polymorphic: true
attr_accessible :number, :phone_type
validates :number, :phone_type, presence: true, on: :save # as suggested in a similar post, just allows blank records into database.
def to_s
"#{phone_type}: #{number}"
end
end
With both the new and edit controller I'm creating a new instance of each of these models so that they show up on the form. #person is loaded in the controller using load_and_authorize_resource as part of cancan.
def new
#person.phones << Phone.new
#person.emails << Email.new
end
Here is the partial view for the form:
<%= simple_form_for #person, :html => { :class => 'form-horizontal' } do |f| %>
<fieldset id="<%= controller.action_name.capitalize %>_person">
<legend><%= controller.action_name.capitalize %> Person</legend>
<%= f.input :prefix %>
<%= f.input :first_name %>
<%= f.input :last_name %>
<%= f.input :job_title %>
<%= f.association :company, :prompt => "Select associated company..." %>
<%= f.simple_fields_for :phones do |phone| %>
<%= phone.input :phone_type, :collection => %w(Work Home Mobile Fax Other), :default => "Work" %>
<%= phone.input :number %>
<% end %>
<%= f.simple_fields_for :emails do |email| %>
<%= email.input :email_type, :collection => %w(Work Home Other), :default => "Work" %>
<%= email.input :email %>
<% end %>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
people_path, :class => 'btn' %>
</div>
</fieldset>
<% end %>
Many thanks for any help in advance :-)

Formtastic nested form field not building has_one association?

Given a User who can possibly be an Artist:
class User < ActiveRecord::Base
has_one :artist
end
I've got a User & Artist nested form (using Formtastic gem):
<h1>Artist registration</h1>
<% #user.build_artist unless #user.artist %>
<%= semantic_form_for #user, :url => create_artist_path do |f| %>
<%= f.inputs :username %>
<%= f.semantic_fields_for :artist do |a| %>
<%= a.input :bio %>
<% end %>
<%= f.buttons do %>
<%= f.commit_button 'Register as Artist' %>
<% end %>
<% end %>
The problem is the :artist fields are not rendered.
I've also tried f.inputs :for => :artist do |a|.
For some reason, using #user.build_artist does not display the artist's fields in the form. If I try #user.artist = Artist.new I get an error, because it tries to save the Artist and validation fails.
How should I initialize the Artist model so I get the benefit of formtastic generators in a nested form? (Note that #user here is not a :new_record?)
Did you remember to set accepts_nested_attributes_for :artist in user.rb?