How do I pass an array to fields_for in Rails? - ruby-on-rails

I want to use fields_for on a subset of records in an association.
I have a Month model, which has_many :payments.
But in my form in my view I only want to have fields_for some of those payments. For example:
- fields_for #month.payments.large
This doesn't work.
Can I pass a set of records to fields_for, rather than the usual symbol (fields_for :payments) approach?

You can add additional association for large payments, for example:
class Month < ActiveRecord::Base
has_many :payments
has_many :large_payments, :class_name => "Payment", :conditions => "value > 1000000"
end
After that you can use fields_for in common way:
- fields_for :large_payments
I think to encapsulate this logic on a model side is a better approach then in the view.

You can, however, use an array of objects without having to create any additional associations. For example, let's say that in your controller you prepared some array of #large_payments, then in the view you can do the following:
<%= f.fields_for :payments, #large_payments do |payment| %> ...
That way if you've got a pretty big form or multiple pages of forms, and you don't want to have to create an additional association for each group that you want to display, you don't have to.

Related

Ruby on rails - nested forms with has_many through

Basically, I want to write a web-based curation tool for clinical conditions (disease) and their underlying genetics. Say, I have a clinical condition (class: Phenotype), and I have "mutations"(class: Genotype) that belong to that condition - either individually (i.e. a given mutation is directly causing this condition) or as a group (two or more mutations together cause the condition). Each condition can have one or more of such groups (i.e. may be cause by different mutations or groups of mutations). So I figured I need to create a grouping class (class: GenotypeGroup) to make that association. What I cannot figure out is how to do the form... First, I would want to enter a phenotype with some description. I then would like to use the "show" view to add a new genotype_group to that phenotype (Add new genotype group). This would have to create, implicitly (since it is basically only a cross-reference table) the genotype_group and one or more genotypes which it links to the phenotype entry.
Right now, I have:
class Phenotype
has_many :genotype_groups
has_many :genotypes, through: :genotype_groups
accepts_nested_attributes_for :genotype_groups
end
class GenotypeGroup
belongs_to :phenotype
has_many :genotypes
accepts_nested_attributes_for :genotypes
end
class Genotype
belongs_to :genotype
end
And zero idea how this would work in terms of nested forms. If anyone has a helpful web resources (been googling for > 1hour now, but apparently don't even know what the thing I am trying to do is called..) - that would be great!
Cheers,
M
Turns out I was missing two things:
a) When nesting the genotype object, I need to add a "Genotype.new" to the nested form element:
<% f.fields_for :genotypes, Genotype.new do |gt| %>
something_here
<% end %>
b) I had to declare which variables should be carried (i.e. are permitted) by the params object in the respective controller(s) so that I could pass those values between the classes during the nested object creation.

Creation of object which doesn't have model, while creation need to create several entries in other tables

In application user can enter new post which contain title, content of the post and category of post. So creating new post will be through some simple html form with few fields. Now i don't know where to put logic for creating new post for following reasons:
Post(or posts collection) is object which is constructed from different tables, for example.
#posts = User.joins(entries: [{storage: :vote}, :category])
.where("votes.count > ?", 0)
.select("users.username AS username,
storages.id AS storage_id,
storages.title AS title,
storages.content AS content,
votes.count AS votes,
categories.category_name AS category_name")
.order("votes.count DESC")
So when user create new post application must create new entries in different tables:
1.Create new entry in entries table. (id, user_id, category_id)
2. Create new entry in storages table.(id, title, content, entry_id)
3. Create new entry in vote table.(id, count, storage_id)
In situation where post is model i can use something like resources: posts then in posts controller through new and create i can create new post, but what in situation like this where i don't need posts controller nor post model? So, question is: which place is more appropriate to put logic for creating new post? Q1
My solution is to craete Storages controller with resource: storages, :only => [:new, :create] then through new and create of this controller to populate different tables in db? I'm forcing here only because i dont see any point of other CRUD actions here(like showing all or one storage), because i will not use storages individually but in conjunction with other tables. So from views/storages through new.html.erb and create.html.erb i can construct new post? Q2
Another solution is to create Post controller which doesn't have "corresponding" post model as i stated before. Here i'm guessing i can't use restful routes(CRUD) because there is not :id of post? I only can make manually non-restful routes like:
post 'posts/create/:title/:content/:category' => 'posts#create', :as => 'create_post' then from params[:title], params[:content] and params[:category] to populate other tables. Q3
Im new to rails so dont yell please :D
This sound like a call for nested forms, its covered in a screen cast
here.
You use the resources of the top model, in this case Entry.
and drill down to the 3rd model.
Simple sample of what to do is bellow.
Model should look like so,
entry.rb
class Entry < ActiveRecord::Base
has_many :storages, :dependent => :destroy
accepts_nested_attributes_for :storages, :allow_destroy => true
end
storage.rb
class Storage < ActiveRecord::Base
belongs_to :entry
has_many :votes, :dependent => :destroy
accepts_nested_attributes_for :votes, :allow_destroy => true
end
vote.rb
class Vote < ActiveRecord::Base
belongs_to :storage
end
and the form should look like so, in simple_form style
<%= simple_form_for #entry do |f| %>
<%= f.simple_fields_for :storages do |storage_fields| %>
<%= storage_fields_for :votes do |vote_fields| %>
<% end %>
<% end %>
<% end %>
and if you have all the models set up, you shouldn't have to do anything to the controller.
This approach is also nice because you can add multiple storages and votes ajax style(without reloading the page) if needed, which is always nice.
I'd use a form class instead of nested attributes any day, see http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/ for an example of this pattern (Chapter "3. Extract Form Objects")
I've used the pattern often enough to gemify it https://github.com/bbozo/simple_form_class and it's used roughly in this way: https://gist.github.com/bbozo/5036937, if you're interested to use it I'll push some docs
EDIT: reason why I tend to go the form class route most of the time is because nested attributes never failed to bite me in the end, either because strong parameter handling got cumbersome, or validators get too complicated (if persisted? else ...), or persistence logic needs to be extended to support some little knack that resolves into callback hell or recursive saves in the model (before/after save spaghetti troubles)

How to eager loading when there are further conditions on association objects?

I am using Ruby on Rails 3.2.2 and I have the following has_many :through association in order to "order articles in categories":
class Article < ActiveRecord::Base
has_many :category_associations # Association objects
has_many :associated_categories, :through => :category_associations # Associated objects
end
class CategoryAssociation < ActiveRecord::Base
acts_as_list :scope => 'category_id = #{category_id} AND creator_user_id = #{creator_user_id}'
belongs_to :associated_article
belongs_to :creator_user, :foreign_key => 'creator_user_id'
end
On retrieving associated_categories I would like to load category_associations objects created by a user (note: the creator user is identified by the creator_user_id column present in the category_associations database table) because I need to display position values (note: the position attribute, an Integer, is required by the act_as_list gem and it is a column present in the category_associations database table) "near" each article title.
Practically speaking, in my view I would like to make something like the following in a proper and performant way (note: It is assumed that each article in #articles is "category-associated" by a user - the user refers to the mentioned creator user of category_associations):
<% #articles.each do |article| %>
<%= link_to(article.title, article_path(article)) %> (<%= # Display the article position in the given category %>)
<% end %>
Probably, I should "create" and "handle" a custom data structure (or, maybe, I should make some else...), but I do not how to proceed to accomplish what I am looking for.
At this time I am thinking that the eager loading is a good approach for my case because I could avoid the N + 1 queries problem since I have to state further conditions on association objects in order to:
retrieve specific attribute values (in my case those refer to position values) of association objects created by a given user;
"relate" (in some way, so that position values are suitable for displaing) each of those specific attribute values to the corresponding associated object.
I think, you are looking for this
#articles = Article.includes(:associated_categories)
This will eager load all your articles including both of its associations (associated_categories, associated_categories). Thus, it will avoid N+1 problem and wont fire queries when you iterate over #articles and its associations in your view.

Using accepts_nested_attributes_for with single table inheritance

I have a model Post which belongs_to one Section. There are two different Section subclasses and I use STI to implement different behavior for each of them. In the Post form I would like to have a tab for each Section. The tab will let the user either A) Pick from an existing Section using a <select> or B) Let the user create a new Section. I would like to know how to use accepts_nested_attributes_for and fields_for or whatever is required to get this done The Rails Way.
Any advice is greatly appreciated. Thanks.
Assuming the tabs correspond to the two subclasses
class Post
# the two subclasses. Each instance will only be using one or the other
belongs_to :section_foo
belongs_to :section_bar
accepts_nested_attributes_for :section_foo
accepts_nested_attributes_for :section_bar
end
And in the view (probably once per tab)
= form_for #post do |f|
= f.select :section_id, SectionFoo.all # etc
= fields_for #post.build_section_foo do |s|
= s.text_field :bla_bla_bla
That should get you 85% of the way there. You might need some :reject_if bidness on the accepts_* to avoid creating a new section and assigning an old section.

Rails 3 Polymorphic Associations Question

I've been trying to switch my Orders model to a polymorphic association with my Product and Service models. However, I have a few questions that I haven't been able to find answers to, even after watching the RailsCast and reading the documentation (so, those suggestions are appreciated, but I need a more concrete answer).
Question:
Is a polymorphic association the best thing to use in this case? Prior to this, I was using a Transaction model that had multiple belongs_to associations and used a custom Parent function to determine which one it was. This was working fine, but someone suggested a polymorphic association may clean things up.
I set up the polymorphic association properly and have been unable to have the transactable_id and transactable_type automatically populated. The code is below. I have side-stepped this by manually putting them in inside the form, but if anyone knows the proper way to do it, that would be great!
How can I access elements with polymorphic associations? For example, in my Cart object (which has_many Transactions and which Transactions belongs_to) I can no longer access things using #cart.transactions.each do |t| ... #t.product.name type coding.
My model associations look like this:
class Order < ActiveRecord::Base
belongs_to :orderable, :polymorphic => true
end
class Product < ActiveRecord::Base
has_many :orders, :as => :orderable
end
My forms used to look like this:
<% form_for [#orderable, #order] do |f| %>
...
<% end %>
And were rendered like this in my Product Show view:
<%= render 'orders/form' %>
Now, I pass a variable for the product.id in the render partial and use it to populate the transactable_id field. But, I feel like that is very messy.
Again, I have read the tutorials and API docs and have been unable to solve this, so any help would be greatly appreciated!!
Answers to your questions:
If your business login implies that multiple models will have related model with the same fields so you should use polymorphic association. (In your case you can use it).
If set up polymorphic association Rails will automatically handle setting *_id and *_type fields depending on associated parent model.
Lets say you have Product with many orders in polymorphic association and you want to define which model order belongs to:
order = Order.first
order.orderable

Resources