Understending STI and Polymorphic associations in rails - ruby-on-rails

According to this answer i'm trying to inplement STI and Polymorphic associations together, my code:
class Post < ActiveRecord::Base
belongs_to :content, :polymorphic => true
end
class Topic < Post #ActiveRecord::Base
has_one :post, :as => :content, :dependent => :destroy
end
class Tutorial < Post #ActiveRecord::Base
has_one :post, :as => :content, :dependent => :destroy
end
In post table i have columns content_id, content_type
and in tables Topic, Tutorial column body
How can i create (in irb) new Tutorial or Topic ?
i tried Post.topics.new(..., :content => {body: 'my_text'})
but get an error

well first of all i can't see STI here as you are inheriting from ActiveRecord in each model and secondly you are creating new topic but your syntax is wrong. Each Topic has one post and each post belongs to a Topic, so you should do something like Topic.post.build(params) to create a post and if you want to create a topic then Post.topic.build(prams)

Related

Selecting 'has_many through' associations in Active Admin

I've seen several questions asked about this along the same vein, e.g.
Using HABTM or Has_many through with Active Admin
but I'm still struggling to get things to work (I've tried multiple ways at this point).
My models (slightly complicated by the 'technician' alias for the user model):
class AnalysisType < ActiveRecord::Base
has_many :analysis_type_technicians, :dependent => :destroy
has_many :technicians, :class_name => 'User', :through => :analysis_type_technicians
accepts_nested_attributes_for :analysis_type_technicians, allow_destroy: true
end
class User < ActiveRecord::Base
has_many :analysis_type_technicians, :foreign_key => 'technician_id', :dependent => :destroy
has_many :analysis_types, :through => :analysis_type_technicians
end
class AnalysisTypeTechnician < ActiveRecord::Base
belongs_to :analysis_type, :class_name => 'AnalysisType', :foreign_key => 'analysis_type_id'
belongs_to :technician, :class_name => 'User', :foreign_key => 'technician_id'
end
I have registered an ActiveAdmin model for the AnalysisType model and want to be able to select (already created) Technicians to associate with that AnalysisType in a dropdown/checkbox. My ActiveAdmin setup currently looks like:
ActiveAdmin.register AnalysisType do
form do |f|
f.input :analysis_type_technicians, as: :check_boxes, :collection => User.all.map{ |tech| [tech.surname, tech.id] }
f.actions
end
permit_params do
permitted = [:name, :description, :instrumentID, analysis_type_technicians_attributes: [:technician_id] ]
permitted
end
end
Whilst the form seems to display okay, the selected technician does not get attached upon submitting. In the logs I'm getting an error 'Unpermitted parameters: analysis_type_technician_ids'.
I've tried multiple ways of doing this following advice in other related SO pages but am always coming up against the same issue, i.e. unpermitted parameterd of some nature. Can anyone point out what I am doing wrong? (I'm using Rails 4 by the way)
Managing the association via has_and_belongs_to_many or has_many relations
does not require the use of accepts_nested_attributes_for. This type of form
input is managing the Technician IDs associated with the AnalysisType record.
Defining your permitted parameters and form like the following should allow
those associations to be created.
ActiveAdmin.register AnalysisType do
form do |f|
f.input :technicians, as: :check_boxes, collection: User.all.map { |tech| [tech.surname, tech.id] }
f.actions
end
permit_params :name, :description, :instrumentID, technician_ids: []
end
In the case where the creation of new Technician records is required that is
when the accepts_nested_attributes_for would be used.
Note: Updated answer to match comments.

RoR has_two relation: a Donation between two Users

I have a problem I find difficult to search the web for an answer...
I have in my Ruby On Rails two models: User and Donation.
I want that a Relation has two user: user1 gives 10$ to user2.
This is what I came with:
class Donation < ActiveRecord::Base
attr_accessible :description, :value, :from_user_id, :to_user_id
def from_user
User.find(from_user_id)
end
def to_user
User.find(to_user_id)
end
end
But I would like to use relationships... Do you know the best way of doing this?
Thanks a lot :)
has_one :from_user, :class_name => 'User', :foreign_key => 'from_user_id'
has_one :to_user, :class_name => 'User', :foreign_key => 'to_user_id'
Relations are nothing special... well, okay, they are now, but this essentially constructs the appropriate sql. I think. Haven't tried it.

Validation of relation models in RoR

How can I validate relations in models in RoR? For example I have 3 models:
class Post < ActiveRecord::Base
belongs_to :blog
has_one :user, :through => :blog
validates :blog_id, :presence => true
end
class Blog < ActiveRecord::Base
belongs_to :user
has_many :posts, :dependent => :destroy
end
class User < ActiveRecord::Base
has_many :blogs
has_many :posts, :through => :blogs
end
And in my controller:
#post = current_user.blogs.find(params[:post].delete(:blog_id)).posts.build(params[:post])
But when I want to create post I get:
Can't mass-assign protected attributes: blog_id
I shouldn't get this error, because I am delete blog_id from params hash, or don't? Any way, what the better way of validating blog_id accessory to User.blogs in my Post model?
If you want to set the on which blog the post should be published after writing, you have to put the blog_id into the whitelist by setting attr_accessible
So in your example your Post model should look like
class Post < ActiveRecord::Base
belongs_to :blog
attr_accessible :blog_id, :title, :content
validates :blog_id, :presence => true
end​
Besides this. Be careful how you set up your relation. The difference between has_one and belongs_to is where the foreign key goes. It goes to where you define the belongs_to. has_one says that one of something is yours, so something points back to you. It doesn't make much sense to say that a Post has_one user...
It is enough to have a Post only belong to a Blog. You still can do something like current_user.posts by how you setup the relationship in the user model like you already did...
I'd recommend reading the following links http://guides.rubyonrails.org/association_basics.html
http://api.rubyonrails.org/classes/ActiveModel/MassAssignmentSecurity/ClassMethods.html
Validations for :blog_id in Post model is perfect.
#post = current_user.blogs.find(params[:post].delete(:blog_id)).posts.build(params[:post])
:blog_id is deleted from params[:post], but let's look at the thing from a different view.
#blog = current_user.blogs.find(params[:post].delete(:blog_id))
#post = #blog.build(params[:post])
params[:post] does not have :blog_id, but build method automatically assigns blog_id to #blog.id.
That's why error for :blog_id is not coming up.
If you wanna avoid the mass assignment warning, you can make the :blog_id attribute accessible.

Polymorphic association validation?

Is there any way to validate that a polymorphic association is only related to one item? for example, if I have a comments that are polymorphic and can be on photos, posts, etc. I want to ensure that if I am adding a comment to a posts' list of comments, that if the comment is already associated with the post, the add will fail. (validation uniqueness error). Any ideas?
So I'm guessing you have something like this:
class Comment < ActiveRecord::Base
belongs to commentable, :polymorphic => true
end
class Post < ActiveRecord::Base
has_many :comments, :as => commentable, :dependent => :destroy
end
class Photo < ActiveRecord::Base
has_many :comments, :as => commentable, :dependent => :destroy
end
Assuming your Comment model has a couple of attributes like author and body (that you want to be unique) then you could create a custom validation in that model like this:
validate do |comment|
if comment.commentable_type.constantize.comments.find_by_author_and_body(comment.author, comment.body)
comment.errors.add_to_base "Duplicate comment added for ..."
end
end
I've also assumed that comments are created something like this:
#post.comments.create(:author => name, :body => comment_text)

rails: self-referential association

My needs are very simple: I have a Tip table to receive comments and have comments to receive comments, too.
To retrieve each comment that is stored in the same table (comments), I created another key for the comments on comments: "inverse_comments".
I tried to use one comments table by using self-referntial association. Some resources seem to bring more than one table into the piture which are diffent from my needs. So I came up whth the following modeling for comments:
class Comment < ActiveRecord::Base
belongs_to :tip
belongs_to :user
has_many :mycomments,
:through => :inverse_comments,
:source => :comment
end
Apparently something is missing here but I cannot figure it out.
Could some one enlighten me on this:
what changes I need to do to make the model work?
thanks.
I believe you should use a polymorphic association.
For that you'll need to add a commentable_id and a commentable_type on your comments table. And your models should look like:
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :commentable, :polymorphic => true
has_many :comments, :as => :commentable
end
class Tip < ActiveRecord::Base
has_many :comments, :as => :commentable
end
This way you can use
#tip.comments
#comment.comments

Resources