Rails & nested comments through partials, strange recursion - ruby-on-rails-4

I've got a pretty simple setting for (polymorphic) comments model which also have a has_many relationship wih itself (called :replies):
# comment.rb
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
default_scope -> { order(created_at: :asc) }
belongs_to :user
belongs_to :comment_parent, class_name: "Comment", foreign_key: "comment_id"
has_many :replies, class_name: "Comment", foreign_key: "comment_id"
validates :content, presence: true
validates :commentable, presence: true
end
In the post controller I fetch the comments:
#comments = #commentable.comments.all()
I'm initiating the partial on my blog view page like so:
= render #comments
And finally the comment/_comment partial containing:
(simpiflied code, this only shows gravatar & username)
# comment/_comment.html.haml
%ol.media-list
%li.media{:class => ("media-replied" if comment.comment_id)}
= link_to gravatar_for(comment.user, size: 80, class_name: 'media-object img-circle'), comment.user, class: 'pull-left'
= render partial: 'comments/comment', collection: comment.replies
Somehow this creates some strange recurrence, in which replies get shown on their correct location, but also on an incorrect location. Problem is that there doesn't seem to be any logic in this. (at least for me it doesn't)
I've checked console to verify that the database contains the correct relations between the records (no faulty records), so it must be in the presentation / partial call.
Any ideas?

Ok, that was my own stupid mistake of course... the call #commentable.comments.all() result is all the comments, so even the nested comments are shown as if they are top level.
Short term fixed it by adding where(comment_id: nil)

Related

passing parameter in has_many through association

I have a class Test, Question, Testquestion associated by has_many through
class Test
has_many :testquestions
has_many :questions, through: :testquestions
end
class Question
has_many :testquestions
has_many :tests, through: :testquestions
end
class Testquestion
belongs_to :test
belongs_to :questions
end
While creating a Test i want to pass a value of column order of Testquestion.
def create
Test.create(test_params)
end
def test_params
params.require(:test).permit(:testname,question_attributes:[:questionname])
end
How should i pass value of order column so that associated model(Testquestion) get updated.
There's no way to do it that way, you will need to take a longer path.
Don't forget to add accepts_nested_attributes_for to your assossiations, so that nested operations would actualy work.
Check that you have added accepts_nested_attributes_for :question to Testquestion.
Get your params structured right.
Something like this:
{
test: {
testname: 'someName',
testquestion_attributes: {
order: someOrder,
question_attributes: {
questionname: 'someName'
}
}
}
}
Require your params.
params.require(:test).permit(:testname, testquestion_params: [:id, :order, :_destroy, question_params: [:id, :questionname])
p.s. sidenote: you should really aquire a habbit of naming your fields and variables in snake_case and your classes in CamelCase.

Retrieve method for a polymorphic, has_one and scoped association

Hi this is somewhat it trivial but I can't for the life of me figure out where to make the adjustments.
I have a LoanApplication model and a transfer model like this:
class LoanApplication < ActiveRecord::Base
before_save :populate_guid
belongs_to :user
has_one :loan, -> { where loan: true }, as: :transferable
has_one :repayment, -> { where repayment: true }, as: :transferable
validates_uniqueness_of :guid
private
def populate_guid
if new_record?
while !valid? || self.guid.nil?
self.guid = SecureRandom.random_number(1_000_000_000).to_s(36)
end
end
end
end
and
class Transfer < ActiveRecord::Base
belongs_to :transferable, polymorphic: true
belongs_to :user
validates_presence_of :transferable_id,
:transferable_type,
:user_id,
:amount,
:password
end
How come LoanApplication.first.loan gives me the following error message
LoanApplication Load (1.1ms) SELECT "loan_applications".* FROM "loan_applications" ORDER BY "loan_applications"."id" ASC LIMIT 1
NameError: uninitialized constant LoanApplication::Loan
All insights appreciated.
Thanks
I think Application is a reserved word. Try to rename LoanApplication?
It was trivial, I just needed to add class_name: "Transfer" for everything to work. -__-'

Nested form with nested has_many, and has_one inside

I am essentially running into the same issue as this post, though I have a slightly different situation: has_many nested form with a has_one nested form within it
But as someone else mentioned in that post, the provided answer does not solve the issue.
The relationship is set up so that Invoice has_many items and each Item has_one Modifier. I am attempting to make a single form_for Invoice that allows a use to create many items, each with a Modifier.
MODELS
class Invoice < ActiveRecord::Base
has_many :items
has_many :modifiers, through: :items
accepts_nested_attributes_for :items
end
class Item < ActiveRecord::Base
belongs_to :invoice
belongs_to :modifier
accepts_nested_attributes_for :modifier
end
class Modifier < ActiveRecord::Base
has_one :item
end
CONTROLLER
class Invoice
def new
#invoice = Invoice.new
end
def edit
end
...
end
VIEWS(haml)
invoice.html.haml:
= form_for #invoice do |f|
= f.text_field :status
= f.fields_for :items do |builder|
= render partial: "items/fields", locals: { :f => builder }
= link_to_add_association 'New Item', f, :items, partial: "items/fields", id: "add-item-button"
items/_fields.html.haml:
.nested-fields
- #item = #invoice.items.build
= f.fields_for :modifier, #item.build_modifier do |modifier|
= modifier.text_field :name
Let's review what's happening. In order to build the nested has_one relationship, I build an Item in the nested-fields partial so that I can build the has_one Modifier. This is because rails requires that you explicitly call 'build_something' in a has_one relationship (usually this is called in the controller's new, but I only want to build once someone has clicked the New Item button). For creating new Invoices, this code works perfectly. Checking console, I see that the relationship is created and I can verify that the Modifier was created successfully.
However, when I go back to edit the invoice, cocoon knows that I already have a modifier, so it calls the partial once to create the necessary fields_for my single Modifier. These fields are empty. This makes sense though, because as cocoon is rendering that partial, it is building a new Code with a new modifier and setting the fields blank. I can confirm that is what is occuring because once I have my modifier saved properly, I can go into my partial, remove the two build calls, and view the edit page which properly displays the saved Modifier info just fine.
Of course, now that I've removed my build calls, the form no longer saves any Modifiers that I create. So essentially, I need the build calls in there to build new Modifiers, but I can't have them in there if I want to view them.
Does anyone have a solution to this situation? I have found multiple stack overflow questions and none of them resolves this issue.
You say has_one but in your model I see has_many ?
You nested partial items/_fields is wrong: you build an extra item and there is not need for that. Coccon, in the link_to_add_association builds a new item to insert.
There are two ways to do what you want to do.
1) In the partial
To handle it correctly in your partial you can do the following (items/_fields.html.haml) :
.nested-fields
- f.object.build_modifier if f.object.new_record?
= f.fields_for :modifier do |modifier|
= modifier.text_field :name
In rails, to refer to the object of the form you can use f.object. Note this will work, but we have to check if it is a newly created object. Alternatively we could just check if the modifier is present.
2) Using the :wrap_object option ( documentation )
Cocoon allows to execute some extra code with the newly created object. So in your case that would become:
= link_to_add_association('New item', f, :items,
:wrap_object => Proc.new { |item| item.build_modifier; item })

Rails 4 - has_many through fetching issue

I have a many to many association wich is being implemented with rails has_many through shortcut.
My models are called:
Cliente
StatusTransacaoPagSeguro
Historico
They were defined this way:
class StatusTransacaoPagSeguro < ActiveRecord::Base
has_many :historicos
has_many :clientes, through: :historicos
end
class Cliente < ActiveRecord::Base
has_many :historicos
has_many :status_transacao_pag_seguros, through: :historicos
end
class Historico < ActiveRecord::Base
belongs_to :cliente
belongs_to :status_transacao_pag_seguro
end
I have the following historico record:
#<Historico id: 1, cliente_id: 3, status_transacao_pag_seguros_id: 3, created_at: "2014-06-01 19:44:42", updated_at: "2014-06-01 19:44:42">
when I run
historico.cliente
I get the associated 'cliente' record, but when I run
historico.status_transacao_pag_seguro
I get nil.
Where's the problem? I defined the pluralization correctly? Since those names are in Portuguese language I think that there's some problem with it but I don't know how to overcome that.
Your FK for status_transacao_pag_seguro in historicos table is wrong. It should be status_transacao_pag_seguro_id (without the s). With the following migration you should be good to go:
def change
rename_column :historicos, :status_transacao_pag_seguros_id, :status_transacao_pag_seguro_id
end

Rails - Multiple Nested Attributes

I am trying to use a select tag to save multiple nested children in a parent.
This is the error I'm looking at
Couldn't find all UserLocations with IDs (1, 2) (found 0 results, but was looking for 2)
I have the following setup under Rails 4 and Devise:
User
class User < ActiveRecord::Base
has_many :user_locations
accepts_nested_attributes_for :user_locations, :allow_destroy => true
end
UserLocation (locations that the user has)
class UserLocation < ActiveRecord::Base
belongs_to :user
belongs_to :location
end
Location (predefined list of locations the user can choose upon)
class Location < ActiveRecord::Base
has_many :user_locations
has_many :users, through: :user_locations
end
However, when trying to save the selected UserLocations, they won't be saved.
Rails Select Tag (You can choose multiple items)
<%= f.select :user_location_ids, options_for_select(Location.all.collect { |l| [ l.name, l.id ] }, #user.user_locations.collect{ |l| l.id }), {}, { multiple: true } %>
I have put the user_location_ids in my application_controller as user_location_ids: []
Cheers
Solved
The solution is to overwrite the default setter method for multiple nested models model_ids=(value). Do not use the plural of the model, e.g. models_ids=(value), because that is wrong!
def user_location_ids=(value)
for slot in value do
unless slot == ""
location = Location.find_by(id: slot.to_i)
unless location.nil?
self.user_locations << UserLocation.create(user_id: self.id, location_id: location.id)
end
end
end
end