Skip to main content

Looking for advice on how to setup a relationship.

Databases • Asked by Morgan

I'm trying to figure out the best way to setup relationships between models which allows users to publish saved content from multiple models.

ExampIe:

I have a Post model which allows users to post and schedule content from other models such as Articles & Reviews.

So it looks something like this:

Post

    t.datetime "scheduled_at"
    t.string "state"
    t.text "error"
    t.boolean "facebook_wall_post"
    t.boolean "facebook_page_post"
    t.boolean "twitter"
    t.boolean "linkedin"

Article

    t.string "title"
    t.text "body"
    t.string "authror"

Review:

    t.string "title"
    t.text "body"
    t.string "rating"

So a User might create a new Article and then optionally choose to post it to Facebook or they may go to /post/new and select the Article from a select field. The can also choose from multiple networks i.e. facebook, twitter etc.

So far I have something like:

class Post < ApplicationRecord
  belongs_to :user
  has_many :articles
  has_many :reviews
end
class Article < ApplicationRecord
  belongs_to :user
  belongs_to :post
end
class Review < ApplicationRecord
  belongs_to :user
  belongs_to :post
end

How would you setup this sort of relationship?


Hey Morgan,

I don't think there's anything inherently wrong with your setup. You may play with a few query scenarios in your console to make sure you're able to access all the objects as you'd expect.

How would you setup this sort of relationship?

If I were doing this, I think I would reverse the associations of Article and Post. Since a Review and Post can't exist without an Article, I think the Article needs to be the main driving model.

class Article < ApplicationRecord
  belongs_to :user
  has_many :reviews
  has_one :post
end
class Post < ApplicationRecord
  belongs_to :user
  belongs_to :article
end
class Review < ApplicationRecord
  belongs_to :user
  belongs_to :article
end

I changed the association between Article and Post to a has_one. There's really no need for an Article to have multiple Post since a single Post object should be sufficient for you to manage the desired behavior.

You'll of course have to update your migrations:

Article

  t.string "title"
  t.text "body"
  t.string "author"

Post

  t.references "article", index: true, foreign_key: true
  t.datetime "scheduled_at"
  t.string "state"
  t.text "error"
  t.boolean "facebook_wall_post"
  t.boolean "facebook_page_post"
  t.boolean "twitter"
  t.boolean "linkedin"

Review

  t.references "article", index: true, foreign_key: true
  t.string "title"
  t.text "body"
  t.string "rating"

Thanks for the detailed reply Jacob!

Just to be clear, Article and Review are content models that belong to a User and don't necessarily have to be shared via Post which means they can exist independently without being associated to a Post.

Basically, all the Post model does is post and schedule content to various sites so it might look like this:

User creates a:
Video -> Post -> YouTube
Article -> Post ->Facebook feed
Review --> Post -> Twitter, Facebook & YouTube
SomeOtherModel -> Post -> Some other network

The reason I'm using a separate (perhaps confusingly named) Post model is that it also handles scheduling via background jobs so it has some extra fields to track errors and status etc.

Would your suggestion still apply in this case?


Ah, your Post model sounds like a good candidate for a polymorphic association.

Article

class Article < ApplicationRecord
  belongs_to :user
  has_many :reviews
  has_many :posts, as: :postable
end

Post

class Post < ApplicationRecord
  belongs_to :postable, polymorphic: true
  belongs_to :user
end

Then all your other models that are postable would be setup like your Article model is with has_many :posts, as: :postable


Your a legend!

It appeasr to be all working now except I'm unnsure how to set the user_id on Post

Post Model

class Post < ApplicationRecord
  belongs_to :postable, polymorphic: true
  belongs_to :user
end

Article Model

class Article < ApplicationRecord
    belongs_to :user
    has_many :posts, as: :postable
end

Review Model

class Review < ApplicationRecord
    belongs_to :user
    has_many :posts, as: :postable
end

Post Controller

class PostsController < ApplicationController
  def create
    # @post = current_user.posts.build(posts_params) << How do I do this now?
    @parent = parent
    @post = @parent.posts.new(post_params)

    respond_to do |format|
      if @post.save
        format.html { redirect_to posts_path, notice: "Post successfully created!"}
      else
        format.html { render :new }
      end
    end
  end

  private

  def parent
    Article.find(post_params[:article_id]) if post_params[:article_id]
    Review.find(post_params[:review_id]) if post_params[:review_id]
  end
end

Just save it before redirecting

def create
    # @post = current_user.posts.build(posts_params) << How do I do this now?
    @parent = parent
    @post = @parent.posts.new(post_params)
    @post.user_id = current_user.id

    respond_to do |format|
      if @post.save
        format.html { redirect_to posts_path, notice: "Post successfully created!"}
      else
        format.html { render :new }
      end
    end
  end

I'm an idiot.

Thanks for all your help Jacob!



Ruby on Rails application services at Inwizards are more than a simple course of action. We start form taking client's perspective and ideas about the app, followed by refining the idea to turn it into something more amazing and realistic. Then we finalize all the stuff, gather all the resources and choose just the right features/design keeping the targeted audience in mind. As an aspiring Ruby on Rails development company of Indian we strive and put our best foot forward towards 100% client satisfaction.
so if you need any type of websites or softwares so please contact with me
skype or gmail-: [email protected]
Get Quotation - http://www.inwizards.com/hire-web≈p-developer.php
any time contact with me i am here wait for your response.


Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 22,346+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.