Rails: concern doesn't load has_one child - ruby-on-rails

If I have a parent class like so:
class Component < ApplicationRecord
include Imageable
end
And that concern looks like so:
module Imageable
extend ActiveSupport::Concern
included do
has_one :image_attachment, as: :imageable, dependent: :destroy
end
end
And that class looks like this:
class ImageAttachment < ApplicationRecord
belongs_to :imageable, polymorphic: true, optional: true
has_attached_file :data
end
Why can't they find each other given these two instances?
ImageAttachment.last
=> <ImageAttachment id: 12, imageable_type: "component", imageable_id: 3, data_file_name: "tumblr_nb88njd2DF1sfwp0ho1_1280.jpg", data_content_type: "image/jpeg", data_file_size: 63794, data_updated_at: "2018-05-02 11:07:12", created_at: "2018-05-02 10:37:48", updated_at: "2018-05-02 11:07:13">
Component.find(3)
=> <Component id: 3, name: "Testing", body: "Test body", created_at: "2017-11-22 02:43:03", updated_at: "2018-05-01 23:50:01">
Component.find(3).image_attachment
=> nil
ImageAttachment.last.component
=> NoMethodError (undefined method `component' for #<ImageAttachment:0x00007fea291ac1e0>)

1) It seems that your imageable_type attribute is wrong, because it should be a class name e.g. 'Component' not 'component'. Rails would not do this by default, so I assume you tampered with that column manually and that is why it is not working
2) ImageAttachment.last.component -> this won't work because your association for ImageAttachment is belongs_to :imageable, so in order to get parent, you need to call ImageAttachment.last.imageable

Related

How do i select an association record that has yet to be saved in Rails?

I have the following models and relationships. I'm building a form and am wanting to initialize terms of the proposal for the form. How can I select a specific ProposalTerm by it's term_type_id to pass on to my fields_for block?
Proposal
class Proposal < ApplicationRecord
after_initialize :add_terms
has_many :terms, class_name: "ProposalTerm", dependent: :destroy
accepts_nested_attributes_for :terms
def add_terms
terms << ProposalTerm.first_or_initialize(type: TermType.signing_bonus)
end
end
ProposalTerm
class ProposalTerm < ApplicationRecord
include DisableInheritance
belongs_to :proposal
belongs_to :type, class_name: "TermType", foreign_key: "term_type_id"
def self.signing_bonus
find_by(type: TermType.signing_bonus)
end
end
My Attempt
>> #proposal.terms
=> #<ActiveRecord::Associations::CollectionProxy [#<ProposalTerm id: nil, season: nil, value: nil, is_guaranteed: false, term_type_id: 2, proposal_id: nil, created_at: nil, updated_at: nil>]>
>> #proposal.terms.where(term_type_id: 2)
=> #<ActiveRecord::AssociationRelation []>
I was able to figure out an answer. I had tried "select" but I was doing it incorrectly.
I had tried the following,
#proposal.terms.select(term_type_id: 2)
but that wasn't returning anything. I then did the following...
#proposal.terms.select { |t| t.term_type_id = 2 }
If you want to return just the first instance use "detect" ...
#proposal.terms.detect { |t| t.term_type_id = 2 } }

Rails 5.1 Multiple belongs_to associations with optional: true, rollback - 'required association'

I want to use belongs_to parent_model, optional: true assocation for 1 child - and 2 parents. Found this answer: Model belongs_to eiher/or more than one models. Tried that. But with 2 associated parent models one of them causes rollback when saving the child model.
Is there any limitation on belongs_to with multiple parent models and optional: true? Or am I missing some other presence validation?
Important to say: I would rather avoid using polymorphic associations in this case.
PrivateAttachment has a file attached using Paperclip.
private_attachment.rb
Class PrivateAttachment < ApplicationRecord
belongs_to :first_class, optional: true
belongs_to :second_class, optional: true
has_attached_file :certificate
validates_attachment_presence :certificate
validates_attachment_size :certificate, :less_than => 10.megabytes
validates_attachment_content_type :certificate,
:content_type => [
"image/jpg",
"image/jpeg",
"image/png",
"application/pdf",
"file/txt",
"text/plain",
"application/doc",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.oasis.opendocument.text",
]
end
first_class.rb
Class FirstClass < ApplicationRecord
validates_length_of :message, :maximum => 2000, allow_blank: true
has_many :private_attachments, dependent: :destroy
has_many :approvals
accepts_nested_attributes_for :approvals
end
second_class.rb
Class SecondClass < ApplicationRecord
has_many :private_attachments, dependent: :destroy
end
When creating PrivateAttachment:
second_class.private_attachments.new(certificate: file)
there's a Rollback on save with a message, despite optional attribute is set to true.
Full error
ActiveModel::Errors:0x00007f8bbe03a380 #base=#PrivateAttachment id:
nil, first_class_id: nil, company_id: nil, user_id: nil, doc_type:
nil, url: nil, active: nil, blind: nil, permit_period: nil, views:
nil, downloads: nil, created_at: nil, updated_at: nil,
certificate_file_name: "test.pdf", certificate_content_type:
"application/pdf", certificate_file_size: 443632,
certificate_updated_at: "2018-07-24 20:18:20", second_class_id: 23>,
#messages={:first_class=>["First class required."]},
**#details={:first_class=>[{:error=>:blank}]}>
When creating Attachment with a first_class, everything works just fine, no error.
UPDATE 1---------------------------------------------------------------------
I just realized, that first_class has a child model Approval which has own validation. But at this point I don't understand why should be this deep assocation being taken into consideration when using optional: true ?
approval.rb
class Approval < ApplicationRecord
belongs_to :job_application
validates_acceptance_of :operator_approval, :allow_nil => false,
end
Rails 5.1.6.
PG DB

Validation Failed using Cocoon for Polymorphic Association

I have the following models in my schema:
class Notification < ApplicationRecord
has_many :impacts, as: :impactable
accepts_nested_attributes_for :impacts, reject_if: :all_blank, allow_destroy: true
end
class Impact < ApplicationRecord
#association
belongs_to :impactable, polymorphic: true
#enum
enum impact_type: [:full_school, :standard, :section]
end
Whenever I try to save a notification now - I get the an error - Validation failed: Impacts impactable must exist
I've tried to create impacts from notifications manually with Notification.last.impacts.create and they work fine.
What could be the problem here?
More info -
When I add a byebug to the #notification object before it saves in the controller - this is the output -
>> #notification
=> #<Notification id: nil, notification_type: "email", title: "Test", content: "Tomorrow is a holiday", created_at: nil, updated_at: nil>
And also checking for it's associations --
>> #notification.impacts
=> #<ActiveRecord::Associations::CollectionProxy [#<Impact id: nil, impact_type: "standard", standard: 2, created_at: nil, updated_at: nil, impactable_id: nil, impactable_type: "Notification", section: "">]>
You just need to add inverse_of: :impactable to your Notifications Model.
has_many :impacts, as: :impactable, inverse_of: :impactable

Rails Find based on a set existing in through a relation

I am trying to select an instance based on a relation of that instance containing a set. A simplified example follows:
class Product::Variation < ActiveRecord::Base
attr_accessible :name, :product_id, :quantity
belongs_to :product
has_many :bids, :foreign_key => :product_variation_id
has_many :product_variation_property_values, :class_name => 'Product::Variation::PropertyValue'
has_many :property_values, :through => :product_variation_property_values, :class_name => 'Property::Value'
end
class Product::Variation::PropertyValue < ActiveRecord::Base
attr_accessible :property_value_id, :variation_id, :property_id
belongs_to :variation
belongs_to :property_value, :class_name => 'Property::Value'
end
class Property < ActiveRecord::Base
attr_accessible :name
has_many :values, :class_name => 'Property::Value'
end
class Property::Value < ActiveRecord::Base
attr_accessible :content
belongs_to :property
belongs_to :partner
end
So now I want to do something like the following (in psuedo code):
Variation.where(:property_values includes [Property::Value.find(1), Property::Value.find(2)])
Is there a way to do this using ActiveRecord?
Thanks and let me know if you need more info.
More Info
I tried the following:
Product::Variation.joins(:property_values).where('property_values.id' => [Property::Value.find(1).id, Property::Value.find(2).id]).first
...which is the following SQL...
SELECT "product_variations".* FROM "product_variations" INNER JOIN "product_variation_property_values" ON "product_variation_property_values"."variation_id" = "product_variations"."id" INNER JOIN "property_values" ON "property_values"."id" = "product_variation_property_values"."property_value_id" WHERE "property_values"."id" IN (1, 2)
...and this returns...
#<Product::Variation id: 25, product_id: 1, quantity: 39, created_at: "2013-11-18 00:18:45", updated_at: "2013-11-18 00:18:45">
But if I do:
Product::Variation.find(25).property_values.inspect
...I get...
[#<Property::Value id: 1, property_id: 1, content: "XS", created_at: "2013-11-18 00:18:45", updated_at: "2013-11-18 00:18:45", color: nil, color_texture: nil, secondary_color: nil>, #<Property::Value id: 6, property_id: 2, content: "Dark Wood", created_at: "2013-11-18 00:18:45", updated_at: "2013-11-18 00:18:45", color: "#855E42", color_texture: "striped", secondary_color: "#FFB90F">]
But I'm looking for the Product::Variation that contains both Property::Value 1 and 2. This is returning those that contain 1 or 2.
This should be doable with a join query. Hard to write form heart, but should be something like this:
Variation.joins(propert_values: :values).where('values.id' => [Property::Value.find(1).id, Property::Value.find(2).id]).first

ActiveRecord, has_many, polymorphic and STI

I've came into a problem while working with AR and polymorphic, here's the description,
class Base < ActiveRecord::Base; end
class Subscription < Base
set_table_name :subscriptions
has_many :posts, :as => :subscriptable
end
class Post < ActiveRecord::Base
belongs_to :subscriptable, :polymorphic => true
end
in the console,
>> s = Subscription.create(:name => 'test')
>> s.posts.create(:name => 'foo', :body => 'bar')
and it created a Post like:
#<Post id: 1, name: "foo", body: "bar", subscriptable_type: "Base", subscriptable_id: 1, created_at: "2010-05-10 12:30:10", updated_at: "2010-05-10 12:30:10">
the subscriptable_type is Base but Subscription, anybody can give me a hand on this?
If the class Base is an abstract model, you have to specify that in the model definition:
class Base < ActiveRecord::Base
self.abstract_class = true
end
Does your subscriptions table have a 'type' column? I'm guessing that Rails thinks that Base/Subscription are STI models. So when a row is retrieved from the subscriptions table and no 'type' column is present, it just defaults to the parent class of Base. Just a guess...

Resources