Skip to content

Instantly share code, notes, and snippets.

@motchang
Last active December 29, 2017 07:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save motchang/665b955351fc9c2afae0c37f3c5dff35 to your computer and use it in GitHub Desktop.
Save motchang/665b955351fc9c2afae0c37f3c5dff35 to your computer and use it in GitHub Desktop.
class Micropost < ApplicationRecord
belongs_to :user
before_save { self.in_reply_to = reply_user }
default_scope -> { order(created_at: :desc) }
mount_uploader :picture, PictureUploader
validates :user_id, presence: true
validates :content, presence: true, length: { maximum: 140 }
validate :picture_size
scope :including_replies, ->(user) { where("user_id = ? OR (user_id IN (SELECT followed_id FROM relationships WHERE follower_id = ?) AND (in_reply_to = ? OR in_reply_to LIKE ?))", user.id, user.id, "", "%@#{user.id}\-#{user.name.sub(/\s/,'-').downcase}%" ) }
private
def picture_size
if picture.size > 5.megabytes
errors.add(:picture, "should be less than 5MB")
end
end
def reply_user
reply_user = ""
if content.match?(/(@[^\s]+)\s.*/)
reply_users = content.scan(/@\d+\-[^\s]+\s/).map do |reply_user|
reply_user.gsub(" ", "")
end
if reply_users.length == 1
reply_user = reply_users[0].downcase
else
reply_user = reply_users.join(", ").downcase
end
end
return reply_user
end
end
class Micropost < ApplicationRecord
const MENTION_REGX = /@\d+\-[^\s]+\s/
belongs_to :user
before_save { self.in_reply_to = reply_user }
default_scope -> { order(created_at: :desc) }
mount_uploader :picture, PictureUploader
validates :user_id, presence: true
validates :content, presence: true, length: { maximum: 140 }
validate :picture_size
# LIKE 文、便利なのですが INDEX が効かずにテーブルスキャン(全行検索)になってしまうので、できればテーブル設計の時点避けたい実装ですね :thinking_face:
# 特に今回のマイクロポストのようにユーザーが大量に文書を投稿するシステムの場合、この実装はしばしば致命的になります。
scope :including_replies, ->(user) { where("user_id = ? OR (user_id IN (SELECT followed_id FROM relationships WHERE follower_id = ?) AND (in_reply_to = ? OR in_reply_to LIKE ?))", user.id, user.id, "", "%@#{user.id}\-#{user.name.sub(/\s/,'-').downcase}%" ) }
private
def picture_size
if picture.size > 5.megabytes
errors.add(:picture, "should be less than 5MB")
end
end
def reply_user
# ファストリターンを積極的に使用してインデントが深くならないような実装を心がけましょう
# 繰り返し現れるリテラルは定数に置き換えたいですね
return "" unless content.match?(Micropost::MENTION_REGX)
reply_users = content.scan(Micropost::MENTION_REGX).map do |reply_user|
reply_user.gsub(" ", "")
end
# ruby の if は if 文ではなく、if 式です。
# if が値を返し、かつこの場合は真偽どちらでも reply_user が返っていたので代入が不要になります。
if reply_users.length == 1
reply_users[0].downcase
else
reply_users.join(", ").downcase
end
# ruby はメソッドの最後に評価された式の値が帰るので return は不要で、かつ上記 if 式が reply_user を返すので return reply_user は不要になります
end
end
end
class Micropost < ApplicationRecord
const MENTION_REGX = /@\d+\-[^\s]+\s/
belongs_to :user
before_save { self.in_reply_to = reply_user }
default_scope -> { order(created_at: :desc) }
mount_uploader :picture, PictureUploader
validates :user_id, presence: true
validates :content, presence: true, length: { maximum: 140 }
validate :picture_size
scope :including_replies, ->(user) { where("user_id = ? OR (user_id IN (SELECT followed_id FROM relationships WHERE follower_id = ?) AND (in_reply_to = ? OR in_reply_to LIKE ?))", user.id, user.id, "", "%@#{user.id}\-#{user.name.sub(/\s/,'-').downcase}%" ) }
private
def picture_size
if picture.size > 5.megabytes
errors.add(:picture, "should be less than 5MB")
end
end
# 空配列も join 可能ですし、正規表現を見直してこうかな
# ex)
# '@1-hogehoge @2-hugahuga message'.scan(/@\d+\-[^\s]+/).join(", ").downcase
# => "@1-hogehoge, @2-hugahuga"
def reply_user
return "" unless content.match?(Micropost::MENTION_REGX)
content.scan(Micropost::MENTION_REGX).join(", ").downcase
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment