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

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.

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 %>

Accessing object in a nested form

i have the following nested form :
<%= form_for #contrat,:url => backend_orders_update_report_url(#contrat) do |f| %>
<%= f.fields_for :contrat_lines do |fcl| %>
<%= fcl.object.inspect %>
<% end %>
<% end %>
the output is the following :
nil
In the nested forms i want to display a few elements not as form but as raw text and a few ones as form field. Usually in a form by doing f.object.name, i would access the name and be able to display it as I want. However, here if i do fcl.object, there is only nil. It should display the inspection of a contrat_line object.
Is it possible to access the data in a nested form?
EDIT :
the controller action :
def show_report
#contrat = Contrat.find(params[:id])
end
Here is what models look like with the relation at the beggining :
ContratLine :
class ContratLine < ActiveRecord::Base
include Priceable
belongs_to :contrat
belongs_to :good
#a enlever ici et dans la base
attr_accessible :active_start,:active,:good_id,:pricing,:contrat
validates :active_start, :presence=> true,:if => "active"
validate :active_start_smaller_than_active_stop
validate :active_start_day_cannot_be_greater_than_28
has_one :pricing, :as => :priceable, :dependent => :delete
before_validation :convert_month_year_to_date
after_save :set_user_subscription_date
Contrat :
class Contrat < ActiveRecord::Base
has_many :contrat_lines, :dependent => :delete_all
belongs_to :user
attr_accessible :user_id,:pricing_id,:state,:adresse_id,:adresse,:payment,:adresse_attributes,:automatic,:start_date,:end_date
enum_attr :state, %w(basket waiting_data to_confirm paid) do
labels :basket=>'Panier', :to_confirm=>'Non payƩ',:paid=>'PayƩ'
end
enum_attr :payment, %w(debit_card wire_transfer cheque direct_debit)
belongs_to :adresse
accepts_nested_attributes_for :adresse, :allow_destroy => true
scope :by_state, lambda { |state| where("state = ?",state) }
scope :last_automatic, where("automatic = true").order("invoice_date DESC")
scope :last_with_adresse, where("state != 'basket'").order("invoice_date DESC")
before_validation :set_numbers
You're missing an accepts_nested_attributes_for :contrat_lines as well as :contrat_lines_attributes in attr_accessible

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 :).

Possible to chain queries in 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

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 %>