Possible to chain queries in Rails 3? - ruby-on-rails-3

I have something like the following
class Group < ActiveRecord::Base
has_many :group_users
end
class GroupUser < ActiveRecord::Base
belongs_to :user, :group
end
class User < ActiveRecord::Base
has_many :group_users
end
The reason I'm not using has_many_through is because the group_user class has more information than just a link table, so I want to be able to access those values.
What I would like to do though is pass #groups to the page and loop through the group users but get at the user object as well
so
<% #groups.each do |group| %>
<%= group.group_user.user.name %>
<% end %>

Here is how I would do it:
User Model
class User < ActiveRecord::Base
has_many :memberships
has_many :groups, :through => :memberships
end
Group Model
class Group < ActiveRecord::Base
has_many :memberships
has_many :users, :through => :memberships
end
Membership Model
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
Controller
def show
#groups = Group.all
end
View
<% #groups.each do |group| %>
<% group.users.each do |user| %>
<%= user.name %>
<% end %>
<% end %>
There are probably a few ways to do it, but this should get you started.
Hope this helps!

If you want to access attributes from the GroupUser model, just do this:
<% #groups.each do |group| %>
<% group.group_users.each do |group_user| %>
<%= group_user.attribute_name %>
<%= group_user.user.name
<% end %>
<% end %>
To make this more efficient from the SQL side of things you can use eager loading:
Group.all(:includes => [:group_users => :user])
F

Related

why are my new and create actions not working with accepts_nested_attributes_for with has_many through?

I'm building a rail 3.2.16 app using 3 models related with a has_many through association but my saving actions are not working. this are my models:
class Cliente < ActiveRecord::Base
has_many :prestamos
accepts_nested_attributes_for :prestamos, reject_if: :all_blank
end
class User < ActiveRecord::Base
has_many :prestamos
has_many :clientes, :through => :prestamos
end
class Prestamo < ActiveRecord::Base
validates_numericality_of :monto, only_integer: true
validates :monto, presence: true
belongs_to :user
belongs_to :cliente, inverse_of: :prestamos
end
When I try to build my #cliente in clientes_controller#new with this
#cliente = current_user.clientes.build
and this in #create
#cliente = current_user.clientes.build(params[:cliente])
and using this view
<%= simple_form_for(#cliente) do |f| %>
<%= f.input :nombre %>
<%= f.input :cedula %>
<%= f.input :direccion %>
<%= f.simple_fields_for :prestamos do |builder| %>
<%= builder.input :monto %>
<% end %>
<%= f.button :submit %>
<% end %>
The render HTML is the expected one, but on save I got the validations errors related to monto in prestamo model. By the way, the monto field is displayed twice.
The erros I having:
Prestamos monto is not a number
Prestamos monto can't be blank
I really hope someone can help me.
Thanks in advance.
Well, I could solve it, but I'm not sure if this is the best way to do it since I'm pretty new in Rails (3 month). This is what I did:
First, I changed my join model Prestamo to this:
class Prestamo < ActiveRecord::Base
attr_accessible :monto, :user_id, :cliente_id
validates_numericality_of :monto, only_integer: true
validates :monto, presence: true
belongs_to :user
belongs_to :cliente, inverse_of: :prestamos
end
The validation were there already, I just added :user_id to the attr_accessible.
2nd, I changed my new and create actions to this:
new:
def new
#cliente = Cliente.new
#cliente.prestamos.build(user_id: current_user.id)
end
create:
#cliente = Cliente.new(params[:cliente])
Finally, I added a hidden field to my form just to store the user_id
<%= form.simple_fields_for :prestamos do |f| %>
<%= f.input :monto %>
<%= f.input :user_id, as: :hidden %>
<% end %>

Form not displayed correctly

i have a form consists of the following models
Employee.rb
class Employee < ActiveRecord::Base
attr_accessible :employee_number, :joining_date, :first_name, :middle_name, :last_name,
:gender, :job_title, :employee_department_id, :qualification, :experience_detail,
:experience_year, :experience_month, :status_description, :date_of_birth, :marital_status,
:children_count, :father_name, :mother_name, :husband_name, :blood_group, :nationality_id,
:home_address_line1, :home_address_line2, :home_city, :home_state, :home_pin_code,
:office_address_line1, :office_address_line2, :office_city, :office_state, :office_pin_code,
:office_phone1, :office_phone2, :mobile_phone, :home_phone, :email, :fax, :user_id,
:reporting_manager_id, :employee_grade_id, :office_country_id,
:home_country_id, :employee_category, :employee_position_id
belongs_to :employee_department
has_many :counselor_supervisors
belongs_to :employee_position
def to_label
full_name = first_name + " " + last_name
end
end
EmployeeDepartment.rb
class EmployeeDepartment < ActiveRecord::Base
attr_accessible :code, :name
has_many :employees
has_many :employee_positions
has_many :counselor_supervisors
has_many :batch_leadership_supervisors
def to_label
name
end
end
CounselorSupervisor.rb
class CounselorSupervisor < ActiveRecord::Base
attr_accessible :employee_id, :employee_department_id, :employee_position_id
belongs_to :employee
belongs_to :employee_department
has_many :batch_counselor_supervisors
def to_label
employee.to_label
end
end
BatchCounselorSupervisor.rb
class BatchCounselorSupervisor < ActiveRecord::Base
attr_accessible :counselor_supervisor_id , :employee_department_id , :counselor_batch_id,
:batch_counselor_advisors_attributes
has_many :batch_counselor_advisors
belongs_to :counselor_supervisor
belongs_to :employee_department
belongs_to :counselor_batch
accepts_nested_attributes_for :batch_counselor_advisors
end
Employee_position.rb
class EmployeePosition < ActiveRecord::Base
attr_accessible :position_title, :employee_department_id
has_many :employees
belongs_to :employee_department
def to_label
position_title
end
end
batch_counselor_supervisors/new.html.erb (part of the form which related to my question)
<%= simple_form_for(#batch_counselor_supervisor) do |f| %>
<%= f.error_messages %>
<%= f.association :employee_department, as: :select %>
<%= f.input :counselor_supervisor_id , collection: EmployeeDepartment.all, as: :grouped_select, group_method: :counselor_supervisors %>
<% end %>
the dropdown list appears like this:
If I added an employee which belongs to the first department "Business Administration", the form will be displayed correctly like this:
Update: after adding label_method: :to_label, so my form became like this :
<%= simple_form_for(#batch_counselor_supervisor) do |f| %>
<%= f.error_messages %>
<%= f.association :employee_department, as: :select %>
<%= f.input :counselor_supervisor_id ,
collection: EmployeeDepartment.all, as: :grouped_select, group_method: :counselor_supervisors, label_method: :to_label %>
<% end %>
the employee name displayed correctly but still the department name not displayed correctly as the following image:
Is this SQLite3 issue ? and What can I do in order to solve this if it sqlite3 issue or not.
From what I see, you only have an issue with the labels not being displayed correctly. Could you try to explicitly set the method on your input:
label_method: :to_label
For more information have a look at https://github.com/plataformatec/simple_form and search for *label_method*
What are the actual relevant rows in your Employee table and your EmployeePosition table?
In your Employee table you happen to have these 2 columns;
employee_position_id
employee_position.
Since employee_position is also a table name, it's bad/reduntant model structure which might be confusing your include method of the query. It's possible that in your tables, the rows are fully filled out to complete the first query, but not for any of your other queries even though you think it is.

jQuery TokenInput plugin with deep nested_attributes pre-populating tokens on edit

I have the following structure working on my application.
class Foo < ActiveRecord::Base
has_many :examples, :dependent => :destroy
accepts_nested_attributes_for :examples
end
class Example < ActiveRecord::Base
belongs_to :foo
has_many :codes, :dependent => :destroy
accepts_nested_attributes_for :codes, :reject_if => lambda { |a| a[:code].blank? }
end
class Code < ActiveRecord::Base
belongs_to :example
has_many :code_kinds
has_many :kinds, :through => :code_kinds
attr_reader :kind_tokens
def kind_tokens=(ids)
self.kind_ids = ids.split(",")
end
end
class CodeKind < ActiveRecord::Base
belongs_to :code
belongs_to :kind
end
class Kind < ActiveRecord::Base
has_many :code_kinds
has_many :codes, :through => :code_kinds
end
And it's working perfectly for the form with fields_for on create and save.
I'm using kind_tokens as described on RailsCast #258 Token Fields
But on the edit form everything displays perfectly now I should be pre-populating the data in a data-pre attribute on the kind_tokens field inside the nested attributes for code in examples.
The RailsCast say:
<%= f.text_field :author_tokens, "data-pre" => #book.authors.map(&:attributes).to_json %>
But I can't do #foo.examples.codes.kinds.map... because the relation with Foo and examples returns a collection, the same situation with codes.
I'm just using:
<%= f.fields_for :codes do |codes_form| %>
That's inside of
<%= f.fields_for :examples do |examples_form| %>
Now how can I pre-populate the kind for code if I don't have any loop, and everything's done by nested_attributes and fields_for ?
Solved
Everytime you use a
<%= f.fields_for ...
Rails automatically makes a loop so you can have some kind of counter there like:
<%
#ctrEx = 0
#ctrCd = 0
%>
<%= form_for #foo ...
<%= f.fields_for :examples do |examples_form| %>
...
<%= examples_form.fields_for :codes do |codes_form| %>
...
<%= codes_form.text_field :kind_tokens, :class => "tag_matcher", "data-pre" => #foo.examples[#ctrEx].codes[#ctrCd].kinds.map(&:attributes).to_json %>
...
<%#ctrCd +=1%>
<%end%>
...
<%
#ctrEx += 1
#ctrCd = 0
%>
<%end%>
<%end%>
Now you can use your counters in the data-pre like this:
#foo.examples[#ctrEx].codes[#ctrCd].kinds.map(&:attributes).to_json
That's the way i figured it out, but there must be another way.

saving record to join table Has_many :through

I am new to Rails 3 and having trouble with saving records in the Join table. I have been looking around and trying different examples found on this website and from the documentation or books, but I don't understand why I can't get it to work. I am trying to create Authorization by creating Roles and associate them to users. So far I have been trying to assign roles from the update action in the Users controller without prevail.
I have 3 models: the User.rb, role.rb, and assignment.rb (the join table)
class User < ActiveRecord::Base
has_many :assignments, :dependent => :destroy
has_many :roles, :through => :assignments, :foreign_key => :role_id
accepts_nested_attributes_for :roles
attr_accessor :password, :role_ids
attr_accessible :first_name, :last_name, :email, :password, :password_confirmation, :status, :description, :username, :roles_attributes
...
end
class Role < ActiveRecord::Base
has_many :assignments
has_many :users, :through => :assignments, :foreign_key => :user_id
accepts_nested_attributes_for :users
attr_accessible :name
end
class Assignment < ActiveRecord::Base
belongs_to :user
belongs_to :role
accepts_nested_attributes_for :roles
end
The Users controller in the update action I have the following
class UsersController < ApplicationController
...
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
#user.roles.build
flash[:success] = "Profile updated"
redirect_to #user
else
#title = "Edit" + " " + #user.username
render 'edit'
end
end
...
end
and in the 'edit' view page I intend to have checkboxes to update the User record with an associated role:
EDIT: Changed the "check_box" with "check_box_tag" ... the check boxes appear properly, but the values are not saved.
<%= form_for(#user) do |f| %>
...
<div class="field">
<%= f.label :roles %><br />
<%= f.fields_for :role_ids do |r| %>
<% #roles.each do |role| %>
<%= check_box_tag "user[roles][]", role.id, #user.roles.include?(role.id) %>
<%= role.name %>
<% end %>
<%= hidden_field_tag "user[roles][]", "" %>
<% end %>
</div>
<% end %>
With this code I even get an error where 'Roles' have no association.
EDIT: this was corrected with the accepts_nested_attributes_for :role. Thanks!
No association found for name `roles'. Has it been defined yet?
I am really confused where I am doing something wrong. Your help would be much appreciated.
Aurelien
You have to use the same name with "accepts_nested_attributes_for" as you used defining the association:
class Assignment < ActiveRecord::Base
belongs_to :user
belongs_to :role
accepts_nested_attributes_for :role
end
Finally solved the problems and thought I could share.
The models associations but I did change the attr_accessible:
class User < ActiveRecord::Base
has_many :assignments, :dependent => :destroy
has_many :roles, :through => :assignments, :foreign_key => :role_id
accepts_nested_attributes_for :roles
attr_accessor :password
attr_accessible ..., :roles_ids
...
end
In the User controller for the edit and update action.
def edit
#title = "Edit" + " " + #user.username
#roles = Role.find(:all)
#user.assignments.build
end
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
redirect_to #user
else
#title = "Edit" + " " + #user.username
render 'edit'
end
end
The important part was the view part and assigning the right names for the checkbox tags
<%= form_for(#user) do |f| %>
<div class="field">
<%= f.label :roles %><br />
<%= f.fields_for :role_ids do |r| %>
<% #roles.each do |role| %>
<%= check_box_tag "user[role_ids][]", role.id, #user.roles.include?(role) %>
<%= role.name %>
<% end %>
<%= hidden_field_tag "user[role_ids][]", #user.id %>
<% end %>
</div>
The check_box_tag lets the form save an array and gives more control than check_box
Then in order to assign the multiple Role ids, the name of the check_box_tag should include user[roles_ids][].
Finally the last parameter of the check_box_tag returns if the User has already the roles and checks the checkboxes if true.
I must admit that the name part of the check_box_tags is really confusing but it works :).

Rails many to one association - Help showing many in one view

These are my models:
class Bedommelse < ActiveRecord::Base belongs_to :virksomhed_primary,
:class_name => 'Virksomhed',
:foreign_key => 'virksomhed_id' belongs_to :virksomheds,
:foreign_key => "virksomhed_id"
end
class Bedommelse < ActiveRecord::Base belongs_to :virksomheds,
:foreign_key => "virksomhed_id" belongs_to :freelances,
:foreign_key => "freelance_id"
end
I am trying to display the name of the virksomhed_id not the id itself in the One View (Bedommelse view)
I can show the column virksomhed_id:
<% #bedommelses.each do |bedommelse| %>
<p><%= bedommelse.virksomhed_id</p>
<% end %>
How do I show the name of the virksomhed?
I have tried this but it didn't work.
<% #bedommelses.each do |bedommelse| %>
<p><%= bedommelse.virksomhed.navn </p>
<% end %>
I have found my mistake
I did a fail in the models:
It should be:
belongs_to :virksomhed
not
belongs_to :virksomheds
And the view should be:
<%= #bedommelse.virksomhed.navn %>