Delete something through relationship table - ruby-on-rails

i have 4 models. I want to delete question, but now i cant. Dont why know. I think, firstly i need delete answer on this questions, then delete inquiry, and then questions itself. Right. But how i can do it?
there my models:
-respondents_model
class Respondent < ActiveRecord::Base
has_many :inquiries
has_many :questions, :through => :inquiries
has_many :answers, :through => :inquiries
end
-answer_model
class Answer < ActiveRecord::Base
belongs_to :inquiry
belongs_to :question
validates_uniqueness_of :inquiry_id
end
-question_model
class Question < ActiveRecord::Base
has_one :answer, :through => :inquiry , :dependent => :destroy
belongs_to :inquiry , :dependent => :destroy
end
-inquiry_model
class Inquiry < ActiveRecord::Base
belongs_to :question
belongs_to :respondent
has_one :answer
end
and my question_controller
def destroy
#question.destroy
head :ok
end

You don't need to delete answers, because they will be automatically deleted as far as you set :dependent => :destroy. So you just need to call:
Also you need to specify WHAT EXACT question are you going to destroy: Question.find params[:id]
def destroy
#question = Question.find params[:id]
#question.destroy
head :ok
end

Related

Rails has many through association setting multiple attributes

So I have a has_many through association where between two tables posts and users:
class Post < ApplicationRecord
has_many :assignments
has_many :users, :through => :assignments
end
class User < ApplicationRecord
has_many :assignments
has_many :posts, :through => :assignments
end
class Assignment < ApplicationRecord
belongs_to :request
belongs_to :user
end
Now in my association table (assignment) there are additional attributes for creator:boolean and editor:boolean.
My question is what's the best way to set these secondary attributes from within the controller?
Having looked around I've got a current solution:
posts_controller.rb:
class PostsController < ApplicationController
def create
params.permit!
#post = Post.new(post_params)
if #post.save
Assignment.handle_post(#post.id, params[:creator], params[:editors])
redirect_to posts_path, notice: "The post #{#post.title} has been created."
else
render "new"
end
end
assignment.rb:
class Assignment < ApplicationRecord
belongs_to :request
belongs_to :user
def self.handle_post(post_id, creator, assignment)
Assignment.where(:post_id => post_id).delete_all
Assignment.create!(:post_id => post_id, :user_id => creator, :creator => true, :editor => false)
if editors.present?
editors.each do |e|
Assignment.create!(:post_id => post_id, :user_id => e, :creator => false, :editor => true)
end
end
end
end
So what is essentially happening is I'm getting the user_ids from the form via params (creator returns 1 id, editors returns an array), and AFTER creating the post I'm deleting all columns associated with the post and recreating them off the new attributes.
The issue I have here is I can't run post validations on these associations (e.g. check a creator is present).
My two questions are as follows:
Is this the correct way to handle secondary attributes?
Is there a way to set the association up and then save it all at once so validations can be performed?
This is a more Rails way to do this:
Use nested attributes
post.rb
class Post < ApplicationRecord
# Associations
has_many :assignments, inverse_of: :post
has_many :users, through: :assignments
accepts_nested_attributes_for :assignments
# Your logic
end
assignment.rb
class Assignment < ApplicationRecord
after_create :set_editors
belongs_to :request
belongs_to :user
belongs_to :post, inverse_of: :assignments
# I would create attribute accessors to handle the values passed to the model
attr_accessor :editors
# Your validations go here
validates :user_id, presence: true
# Your logic
private
def set_editors
# you can perform deeper vaidation here for the editors attribute
if editors.present?
editors.each do |e|
Assignment.create!(post_id: post_id, user_id: e, creator: false, editor: true)
end
end
end
end
And finally, add this to your PostsController
params.require(:post).permit(..., assignments_attributes: [...])
This allows you to create Assignments from the create Post action, will run validations on Post and Assignment and run callbacks for you.
I hope this helps!

How to apply association rules

I'm confusing about association.
I tried to write code below but rails was returned me "undefined method `subs'".
def show
#product = Product.find(params[:id])
#materials = #product.materials.subs
respond_to do |format|
format.json { render json: [ #product,#materials ]}
end
end
I want Product model relates to Sub model and I get Sub model record.
If someone knows about this problem to solve please tell me.
class Product < ActiveRecord::Base
has_many :product_materials
has_many :materials, :through => :product_materials
end
class ProductMaterial < ActiveRecord::Base
belongs_to :product
belongs_to :material
end
class Material < ActiveRecord::Base
has_many :product_materials
has_many :products, :through => :product_materials
has_many :material_subs
has_many :subs, :through => :material_subs
end
class MaterialSub < ActiveRecord::Base
belongs_to :material
belongs_to :sub
end
class Sub < ActiveRecord::Base
has_many :material_subs
has_many :materials, :through => :material_subs
end
#product.materials is an array and you cannot chain a association on an array
#product = Product.includes(materials: :subs).find(params[:id])
#materials = #product.materials.flat_map(&:subs)
this will loop over the materials and will return subs for each material

polymorphic association belongs to User

I have a comments model which is a polymorphic association which is involved with Statuses and Photos. How can I create this polymorphic association to also belong to a User so that when a user creates a comment under statuses or photos it will also recieve the current_user id?
this is what I have as of now-
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
belongs_to :user
end
class User < ActiveRecord::Base
has_many :comments
end
class Status < ActiveRecord::Base
has_many :comments, as: :commentable
end
class Photo < ActiveRecord::Base
has_many :comments, as: :commentable
end
just to reiterate, how can I create a comment as a user but also have it under status or photo? it would need the user_id.
This is where I am having the trouble-
how should I set this up?
def create
#comment = #commentable.comments.new(comments_params)
if #comment.save
redirect_to #commentable, notice: "Comment created"
else
render :new
end
end
Try this
class Comment < ActiveRecord::Base
belongs_to :likable, :polymorphic => true
belongs_to :commentable, :polymorphic => true
belongs_to: user
class User < ActiveRecord::Base
has_many :statuses, :as => :likable
has_many :photos, :as => :commentable
has_many :comments
class Status < ActiveRecord::Base
has_many :comments, :as => :likable, :dependent => :destroy
class Photos < ActiveRecord::Base
has_many :comments, :as => :commentable, :dependent => :destroy
It's a little bit hacky but I found a workaround. So in my CommentsController i did this:
def create
new_params = comments_params
new_params[:user_id] = current_user.id
#comment = #commentable.comments.build(new_params)
if #comment.save
redirect_to #commentable, notice: "Comment created"
else
render :new
end
end
that placed the user_id which is what I needed.

Dependent destroy does not destroy dependencies

I have the following models:
class Article < ActiveRecord::Base
has_many :comments, :as => :subject, :dependent => :destroy
has_many :deleted_comments, :as => :subject, :dependent => :destroy
end
class DeletedComment < ActiveRecord::Base
belongs_to :subject, :polymorphic => true
end
class Comment < ActiveRecord::Base
belongs_to :subject, :polymorphic => true
before_destroy :create_deleted_comment
def create_deleted_comment
DeletedComment.create!(....)
end
end
In my database, I have quite a few DeletedComment objects where the subject is nil. The DeletedComment (and Comment) model stores :article_id, and for the ones where the subject is nil, Article.find(deleted_comment.article_id) raises an ActiveRecord::RecordNotFound error.
Are there any cases where the :dependent => :destroy would destroy the parent record but leave the dependencies untouched?
Is it possible that in some cases when I delete an Article the deleted_comments are destroyed before comments? and when the comments are destroyed, deleted_comments are created and not destroyed (because ActiveRecord has already checked the dependent deleted_comment and tried to destroy any dependencies)?
According to official documentation:
Using polymorphic associations in combination with single table inheritance (STI) is a little tricky. In order for the associations to work as expected, ensure that you store the base model for the STI models in the type column of the polymorphic association. To continue with the asset example above, suppose there are guest posts and member posts that use the posts table for STI. In this case, there must be a type column in the posts table.
class Asset < ActiveRecord::Base
belongs_to :attachable, polymorphic: true
def attachable_type=(sType)
super(sType.to_s.classify.constantize.base_class.to_s)
end
end
class Post < ActiveRecord::Base
# because we store "Post" in attachable_type now dependent: :destroy will work
has_many :assets, as: :attachable, dependent: :destroy
end
class GuestPost < Post
end
class MemberPost < Post
end
I guess you could use examle and do something like:
class Article < ActiveRecord::Base
# for deletion only
has_many :abstract_comments, :as => :subject, :dependent => :destroy
# for 'manual' access/edition
has_many :comments, :as => :subject
has_many :deleted_comments, :as => :subject
end
class AbstractComment < ActiveRecord::Base
belongs_to :subject, :polymorphic => true
def attachable_type=(sType)
super(sType.to_s.classify.constantize.base_class.to_s)
end
end
class DeletedComment < AbstractComment
end
class Comment < AbstractComment
before_destroy :create_deleted_comment
def create_deleted_comment
DeletedComment.create!(....)
end
end

Are my ActiveRecord associations setup correctly? (simple message board application)

Basically I want a Topic to have many Posts and Posts to have many Comments. If a Post gets destroyed I want it's Comments to be destroyed. If a Topic is deleted, I want it's Posts and Comments destroyed. Does the code below accomplish this? And is the has_one :topic line necessary?
topic.rb:
class Topic < ActiveRecord::Base
has_many :posts, :dependent => :destroy
end
post.rb:
class Post < ActiveRecord::Base
belongs_to :topic, :dependent => :destroy, :touch => true
has_one :topic
has_many :comments, :dependent => :destroy
end
comment.rb:
class Comment < ActiveRecord::Base
belongs_to :post, :dependent => :destroy, :touch => true
end
Should I be using the Ancestry gem for this? Would that make this even more simple? Thanks for reading my questions. Any assistance would be greatly appreciated.
1) has_one :topic is unnecessary, with the belongs_to you already declare the association.
2) :dependent => :destroy goes on the has_many side for your requirements. If you place them on the belongs_to side you will destroy a Topic once destroying one of his posts, leaving orphan a lot of other posts.
This is the code you're looking for:
topic.rb:
class Topic < ActiveRecord::Base
has_many :posts, :dependent => :destroy
end
post.rb:
class Post < ActiveRecord::Base
belongs_to :topic, :touch => true
has_many :comments, :dependent => :destroy
end
comment.rb:
class Comment < ActiveRecord::Base
belongs_to :post, :touch => true
end

Resources