I finished Hartl’s tutorial and have been trying to add twitter-like @replies for the past few days to no avail. I added an in_reply_to column to the Microposts table as an integer that I thought could be used to reference a given user’s id. As of now I’m using a regex to search for a match with a given user’s name via the Microposts controller.
Hartl suggests using an including_replies scope in the Micropost model. I’ll admit I’m not quite sure what to include in this scope based on what automatic associations rails creates or what I have to tell it.
Any assistance would be greatly appreciated.
User Model
has_many :microposts, dependent: :destroy
has_many :replies, through: :microposts, source: :in_reply_to
VALID_NAME_REGEX = /\A[\w+\-.]\z/i
validates :name, presence: true,
format: { with: VALID_NAME_REGEX },
length: { maximum: 20 },
uniqueness: { case_sensitive: false }
...
def feed
Micropost.from_users_followed_by(self)
Micropost.including_replies
end
Micropost Model
class Micropost < ActiveRecord::Base
attr_accessible :content
belongs_to :user
belongs_to :in_reply_to, class_name: "User"
validates :user_id, presence: true
validates :content, presence: true, length: { maximum: 140 }
default_scope order: 'microposts.created_at DESC'
scope :including_replies, where("user_id = in_reply_to")
def self.from_users_followed_by(user)
followed_user_ids = "SELECT followed_id FROM relationships
WHERE follower_id = :user_id"
where("user_id IN (#{followed_user_ids}) OR user_id = :user_id",
user_id: user.id)
end
end
Microposts Controller
class MicropostsController < ApplicationController
before_filter :signed_in_user, only: [:create, :destroy]
before_filter :correct_user, only: :destroy
before_filter :reply_to_user, only: :create
def create
@micropost = current_user.microposts.build(params[:micropost])
if @micropost.save
flash[:success] = "Micropost created!"
redirect_to root_path
else
@feed_items = []
render 'static_pages/home'
end
end
def destroy
@micropost.destroy
redirect_to root_path
end
private
def correct_user
@micropost = current_user.microposts.find_by_id(params[:id])
redirect_to root_path if @micropost.nil?
end
def reply_to_user
if reply_to = @micropost.content.match(/\A(@[\w+\-.])\z/i)
@other_user = User.where(name: reply_to.to_s[1..-1])
if @other_user && current_user.followed_users.includes(@other_user)
@micropost.in_reply_to = @other_user.id
end
end
end
end
I’ve started to look into this and the first thing I’ve noticed is that your regexp looking for replies doesn’t work:
So the first tip: test every bit you’re implementing.
Also, I think you got the association wrong, I used
(I’ve renamed the key from in_reply_to to simply “to” because there was a strange deprecation warning when using the underscores).
but you mainly asked how to define the new scope in Micropost. I did it like this:
…
I hope that helps. you can have a look at my whole implementation at
https://github.com/htw-rails/TutorialSampleApp32/tree/reply