Is there such a thing as .current in Ruby/Rails?
I have the following in my Release model to accept tracks as nested attributes. I'm using :after_add to manually set the position column in the has_many through join table. I ideally want this to be populated from either the position attribute sent from the fields_for part of my form or copied from the value set in the tracks table/model on save.
I can get it to set the first or last positions on all entries, but not the current position that relates to that track?
I ideally need releases_tracks.each { |t| t.position = self.tracks.last.position } to be something like releases_tracks.each { |t| t.position = self.tracks.current.position }
has_many :releases_tracks, :dependent => :destroy, :after_add => :position_track
has_many :tracks, :through => :releases_tracks, :order => "position"
accepts_nested_attributes_for :tracks, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => :true
accepts_nested_attributes_for :releases_tracks
def position_track(track)
releases_tracks.each { |t| t.position = self.tracks.last.position }
end
Can anyone help?
Can't say for sure if I understood you correctly, but, as far as I can tell, releases_tracks.each { |t| t.position = t.track.position } should solve your problem.
belongs_to - has_many relationship works two ways, so for two models «Owner» and «Belonging» bound by such relationship both Owner.first.belonging and Belonging.last.owner queries are valid.
Related
An element can be associated with different models through the polymorphic association elementable. Because I want to use nested forms, I have to make associations for the different models explicit (association element_recommendation).
The following code works as intended:
class Element < ActiveRecord::Base
belongs_to :elementable, :polymorphic => true, :dependent => :destroy
belongs_to :element_recommendation, ->(element) {
if element.elementable_type == 'ElementRecommendation'
where('true = true')
else
none
end }, :class_name => "ElementRecommendation", :foreign_key => "elementable_id"
[..]
But I'm unhappy with the lambda in the element_recommendation association. It's an all or nothing association. The none-part is cognizable, but the take it as it is-part is not obvious. How can I make where('true = true') recognizable?
I've found the solution while I was writing the question:
belongs_to :element_recommendation, ->(element) {
if element.elementable_type == 'ElementRecommendation'
self
else
none
end }, :class_name => "ElementRecommendation", :foreign_key => "elementable_id"
Here's the (simplified) code:
class Biosimilar::AdverseEvent < ActiveRecord::Base
attr_accessibile :adverse_event_med_conds_attributes
has_many :adverse_event_med_conds,
:class_name => 'Biosimilar::AdverseEventMedCond',
:dependent => :destroy
has_many :med_conds,
:class_name => 'Biosimilar::MedCond',
:through => :adverse_event_med_conds
accepts_nested_attributes_for :adverse_event_med_conds,
:allow_destroy => true,
:reject_if => proc { |attributes| attributes.any? {|k,v| v.blank?} }
end
When the form is submitted, the record is created on "adverse_event_med_conds" table even if the user leaves the "med_cond_id" field EMPTY. The reject_if doesn't work!
Any suggestions?
Ok, forget it. The above code is correct! The problem was in the controller, I accidentally left in the "show" method the following lines:
if #adverse_event.adverse_event_med_conds.size == 0
#adverse_event.adverse_event_med_conds.build
end
...and the "build" call was the one that caused record creation.
my problem is following. How can I joins belongs_to association from polymorphic model
There is situation
opinion.rb
class Opinion < ActiveRecord::Base
belongs_to :opinionable, :polymorphic => true
belongs_to :category
end
answer.rb
class Answer < ActiveRecord::Base
has_many :opinions, :as => :opinionable
end
How can i do following
Opinion.joins(:opinionabe).all
it will throw
ArgumentError: You can't create a polymorphic belongs_to join without specifying the polymorphic class!
How can i specific which class i want to join?
Second question. How to preload it?
Opinion.preload(:opinionable).all
works fine. It will do query for each class in belongs_to.
But. if i want to do something like
Opinion.preload(:opinionable => :answer_form).all
there is problem because one model has this association and second hasn't. So it will throw exception.
So how i can do something like
Opinion.preload(:answer => :answer_form, :another_belongs_to_model).all
?
Thanks, David!
Actually if you just do
belongs_to :opinionable_answer, :foreign_key => :opinionable_id, :class_name => "Answer", conditions: { opinions: { opinionable_type: "Answer"}}
then you can do
Opinion.joins(:opinionable_answer).where(answers: { awesome: true})
It looks like you have not specified opinionable_type:string column for your Opinion model.
Try to update your migration in this manner:
class CreateOpinions < ActiveRecord::Migration
def self.up
create_table :opinions do |t|
t.integer :opinionable_id
t.string :opinionable_type
# ... other fields
t.timestamps
end
end
def self.down
drop_table :opinions
end
end
This will solve your second question and Opinion.preload(:opinionable).all should work well.
You cann't do joins on polymorphic association because they can be located in different tables, which are detected after Opinion model is loaded. That why model needs column opinionable_type.
If you try to do this you'll get next exception
ActiveRecord::EagerLoadPolymorphicError: Can not eagerly load the polymorphic association :opinionable
UPD: Added magic join ^_^
class Opinion < ActiveRecord::Base
belongs_to :opinionable, :polymorphic => true
belongs_to :opinionable_answer, :foreign_key => :opinionable_id, :class_name => "Answer"
scope :by_type, lambda { |type| joins("JOIN #{type.table_name} ON #{type.table_name}.id = #{Opinion.table_name}.opinionable_id AND #{Opinion.table_name}.opinionable_type = '#{type.to_s}'") }
end
Example:
Opinion.by_type(Answer).to_sql
=> "SELECT \"opinions\".* FROM \"opinions\" JOIN answers ON answers.id = opinions.opinionable_id AND opinions.opinionable_type = 'Answer'"
I know this question is old but I just spent an hour looking for the solution to a similar problem (Rails 3) and the only way I got it to work was the solution stated here: https://stackoverflow.com/a/25966630/6878997
Which, in your case would be:
class Opinion < ActiveRecord::Base
# The true polymorphic association
belongs_to :opinionable, polymorphic: true
# The trick to solve this problem
has_one :self_ref, :class_name => self, :foreign_key => :id
has_one :answer, :through => :self_ref, :source => :opinionable, :source_type => Answer
end
Seems tricky but this way you will be able to do multiple chained joins such as:
joins(answer: :other_model).
And whenever opinion.opinionable is not an Answer, opinion.answer will return nil.
Hope it helps somebody!
I have a table with entries, and each entries can have different account-types. I'm trying to define and return the account based on the value of cindof
Each account type has one table, account_site and account_page. So a regular belongs_to won't do.
So is there any way to return something like:
belongs_to :account, :class_name => "AccountSite", :foreign_key => "account_id" if cindof = 1
belongs_to :account, :class_name => "AccountPage", :foreign_key => "account_id" if cindof = 2
Have tried to do that in a method allso, but no luck. Really want to have just one accountand not different belongs_to names.
Anyone that can figure out what I want? Hard to explain in English.
Terw
You should be able to do what you want with a polymorphic association. This won't switch on cindof by default, but that may not be a problem.
class ObjectWithAccount < ActiveRecord::Base
belongs_to :account, :polymorphic => true
end
class AccountSite < ActiveRecord::Base
has_many :objects_with_accounts,
:as => :account,
:class_name => 'ObjectWithAccount'
end
class AccountPage < ActiveRecord::Base
has_many :objects_with_accounts,
:as => :account,
:class_name => 'ObjectWithAccount'
end
You will need both an account_id column and a account_type column. The type of the account object is then stored in the extra type column.
This will let you do:
obj.account = AccountPage.new
or
obj.account = AccountSite.new
I would look into Single Table Inheritance. Not 100% sure, but I think it would solve your problem http://code.alexreisner.com/articles/single-table-inheritance-in-rails.html
If that isn't good, this isn't too hard to implement yourself.
def account
case self.cindof
when 1 then AccountSite.find self.account_id
when 2 then AccountPage.find self.account_id
end
end
When using the new accepts_nested_attributes_for in ActiveRecord, it's possible to use the option :allow_destroy => true. When this option is set, any hash containing nested attributes like {"_delete"=>"1", "id"=>"..."} passed to update_attributes will delete the nested object.
Simple setup:
class Forum < ActiveRecord::Base
has_many :users
accepts_nested_attributes_for :users, :allow_destroy => true
end
class User < ActiveRecord::Base
belongs_to :forum
end
Forum.first.update_attributes("users_attributes"=>{"0"=>{"_delete"=>"1", "id"=>"42"}})
Question: How do I - instead of deleting the nested objects when "_delete" => "1" - just remove the association? (i.e. In the above case set the forum_id on the user to nil)
Bonus question: What if I also want to change the an attribute on the nested object when removing the association? (e.g. like setting a state or a timestamp)
Instead of asking for the user to be deleted using "_delete" => '1', can you not just update it using the nested_attributes?:
Forum.first.update_attributes("users_attributes"=> {
"0" => {
"id" => "42",
"forum_id" => "",
"state" => 'removed'
}
})