Reputation: 387
I've been creating an application which has several different model types which act as different page types.
I currently have a Posts model with two polymorphic attributes: Postable and Posterable, where these are the pages on which posts are posted, and the authors of each post respectively.
For example, I want users to be able to author and receive a post, whilst I also want a Group to be able to receive a post and author one via an admin user.
My Post model is currently as follows:
class Post < ActiveRecord::Base
before_create :set_latlong
belongs_to :posterable, polymorphic: true
belongs_to :postable, polymorphic: true
default_scope -> { order('created_at DESC') }
validates :content, presence: true, length: { maximum: 140 }
validates :posterable_id, presence: true
validates :posterable_type, presence: true
def set_latlong
self.latitude = posterable.latitude
self.longitude = posterable.longitude
end
def self.from_users_favourited_by(user)
favourited_user_ids = "SELECT favourite_id FROM favouriteusers
WHERE favourited_id = :user_id"
where("posterable_id IN (#{favourited_user_ids}) OR posterable_id = :user_id", user_id: user.id)
end
end
Post scheme is:
create_table "posts", force: true do |t|
t.string "content"
t.integer "posterable_id"
t.string "posterable_type"
t.float "latitude"
t.float "longitude"
t.integer "postable_id"
t.string "postable_type"
t.datetime "created_at"
t.datetime "updated_at"
end
I believe these are all workable too allow for various models to post on various model pages. However, I'm not quite sure how to implement this quite yet, the Post controller is as follows:
class PostssController < ApplicationController
before_action :authenticate_user!, only: [:create, :destroy] before_filter :load_posterable
def new @post = Post.new(post_params) end
def create @posterable = load_posterable @post = @posterable.posts.build(post_params) @post.postable = find_postable if @post.save flash[:success] = "Post created!" redirect_to root_url else @feed_items = [] render 'static_pages/home' end end
def destroy @post = Post.find(params[:id]) if @post.present? @post.destroy end redirect_to root_url end
private
def post_params
params.require(:post).permit(:content)
end
def load_posterable
resource, id = request.path.split('/')[1, 2]
resource_name = resource.singularize.classify
if resource_name = "user"
@posterable = current_user
else
@posterable = resource_name.constantize.find(id)
end
end
def find_postable
resource, id = request.path.split('/')[1, 2]
resource_name = resource.singularize.classify
end
end
I believe the key to making this work is separating the "resource" in the load_posterable and find_postable methods, which I got from the Railscast tutorial on polymorphic association, but I don't really know how I would differentiate between these within the same model?
Upvotes: 1
Views: 451
Reputation: 10593
Ok, so you need a Profile model, which user/admin will use to act on the site with.
You should create and select it automatically for users (default one), and then separate one for each group one becomes an admin of.
Profile in itself should not really hold any attributes, just delegate them over association (maybe a polymorphic one if you wish) to the user or other model.
This way you have quite a clean interface, Profile class will be kind-of decorator for your models.
On controller level you should have a current_profile
method similar to current_user
in Devise which will store/retrieve profile id from session.
See: http://en.wikipedia.org/wiki/Decorator_pattern
Upvotes: 0