2012-07-18 51 views
1

我知道我在这篇文章中要求很多,但是在阅读了4本有关Ruby/Rails的书籍之后,我感到沮丧的是我没有得到“aha”时刻。如果有人能帮忙,我会过来给你煮早餐(一周)。Ruby on Rails 3教程练习no。 1提示

我来自PHP/MySQL的世界,我发现很难在Rails中掌握某些东西。 Michael Hartl读过的最后一本书提出了一些练习,以增加他在书中构建的应用程序。它与社团有关。所以我想知道如果有人可以给我一些提示如何去做这件事,因为我真的被卡住了。

他构建的应用程序几乎是一个Twitter克隆。有发布Microposts的用户。他们的主页看起来像这样http://ruby.railstutorial.org/chapters/following-users#fig:home_page_with_feed用户自己的Microposts被放在'feed'的右边。与Feed中用户的Microposts一起的还有当前用户所遵循的用户Microposts。您可以关注并取消关注您想要的任何用户。

该练习建议添加@replies。 @reply是以@username开头的Micropost(例如'@mikeglaz你好吗')。此Micropost将出现在您的Feed和用户名的Feed中(不一定是您关注的人)。作者提出以下建议:'这可能涉及在microposts表中添加in_reply_to列,并向Micropost模型中添加一个包含范围的范围。'但关于跟随其他用户的联系非常复杂,这就是让我陷入困境的原因。我会后一些代码:

用户

class User < ActiveRecord::Base 
    attr_accessible :email, :name, :password, :password_confirmation 
    has_secure_password 
    has_many :microposts, dependent: :destroy 
    has_many :relationships, foreign_key: "follower_id", dependent: :destroy 
    has_many :followed_users, through: :relationships, source: :followed 
    has_many :reverse_relationships, foreign_key: "followed_id", 
     class_name: "Relationship", 
     dependent: :destroy 
    has_many :followers, through: :reverse_relationships, source: :follower 

    def feed 
    Micropost.from_users_followed_by(self) 
    end 

    def follow!(other_user) 
    relationships.create!(followed_id: other_user.id) 
    end 

    def unfollow!(other_user) 
    relationships.find_by_followed_id(other_user.id).destroy 
    end 
end 

end 

关系

class Relationship < ActiveRecord::Base 
    attr_accessible :followed_id 

    belongs_to :follower, class_name: "User" 
    belongs_to :followed, class_name: "User" 
end 

微柱

class Micropost < ActiveRecord::Base 
    attr_accessible :content 
    belongs_to :user 

    def self.from_users_followed_by(user) 
    followed_user_ids = user.followed_user_ids 
    where("user_id IN (?) OR user_id = ?", followed_user_ids, user) 
    end 
end 

回答

0

嗯,世界卫生大会你的具体问题?你根本不需要看看复杂的用户关联,这是一个提示! (我发现他们也感到困惑,所有的跟随和后面都有,但是改变主要是进入Micropost模式,所以你应该从Michael Hartl给出的提示开始。

如果你想,你可以在我的解决方案,我得到14天前在

https://github.com/htw-rails/TutorialSampleApp32/

  • 一些源代码可能看起来有点不同偷看,因为这个版本已经发展出了教程为Rails的3.0版本。
+0

我感谢你的帮助@bento。 – mikeglaz 2012-07-30 22:30:30

0

请注意,我通过使用用户名....找到人,并且我特别添加了允许@reply工作的代码。你应该已经与轨道教程由迈克尔·哈特尔

数据库已经完成

class CreateRecipients < ActiveRecord::Migration 
    def change 
    create_table :recipients do |t| 
     t.string :user_id 
     t.string :micropost_id 

     t.timestamps 
    end 
    end 

    def self.down 
    drop_table :recipients 
    end 
end 

模型

class Recipient < ActiveRecord::Base 
    attr_accessible :micropost_id, :user_id 

    belongs_to :user 
    belongs_to :micropost 

end 


class Micropost < ActiveRecord::Base 
    attr_accessible :content, :recipients 
    belongs_to :user 

    USERNAME_REGEX = /@\w+/i 

    has_many :recipients, dependent: :destroy 
    has_many :replied_users, :through => :recipients, :source => "user" 

    scope :from_users_followed_by, lambda { |user| followed_by(user) } 

    after_save :save_recipients 

    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 

    private 

    def self.followed_by(user) 
     followed_ids = %(SELECT followed_id FROM relationships 
        WHERE follower_id = :user_id) 
     micropost_ids = %(SELECT micropost_id FROM recipients 
        WHERE user_id = :user_id) 
     where("id IN (#{micropost_ids}) OR user_id IN (#{followed_ids}) OR user_id", 
     {:user_id => user}) 
    end 

    def save_recipients 
     return unless reply? 

     people_replied.each do |user| 
     Recipient.create!(:micropost_id => self.id, :user_id => user.id) 
     end 
    end 

    def reply? 
     self.content.match(USERNAME_REGEX) 
    end 

    def people_replied 
     users = [] 
     self.content.clone.gsub!(USERNAME_REGEX).each do |username| 
     user = User.find_by_username(username[1..-1]) 
     users << user if user 
     end 
     users.uniq 
    end 
end 


class User < ActiveRecord::Base 
    attr_accessible :name, :email, :password, :password_confirmation, 
        :username 
    has_secure_password 

    before_save { |user| user.email = email.downcase } 
    before_save :create_remember_token 

    VALID_EMAIL_REGEX = /\A[\w+\-.][email protected][a-z\d\-.]+\.[a-z]+\z/i 
    VALID_UNAME_REGEX = /^[a-z](\w*[a-z0-9])*$/i 

    has_many :micropost, dependent: :destroy 

    has_many :relationships, foreign_key: "follower_id", dependent: :destroy 
    has_many :followed_users, through: :relationships, source: :followed 

    has_many :reverse_relationships, foreign_key: "followed_id", 
            class_name: "Relationship", 
            dependent: :destroy 
    has_many :followers, through: :reverse_relationships, source: :follower 

    has_many :replies, :class_name => 'Recipient', :dependent => :destroy 
    has_many :received_replies, :through => :replies, :source => 'micropost' 

    def to_param 
    self.username 
    end 

end 
0

我的解决方案并没有涉及任何的has_many:协会或范围。它可能更粗糙,但它似乎工作。

这是我做过什么:

  1. 新增user_name到用户
  2. 新增in_reply_to到微柱
  3. 在控制器中使用正规式扫描新职位的@user_name并挑选出相关USER_ID
  4. 将该user_id保存在微博的in_reply_to
  5. 添加到订阅源的SQL查询以挑选出位置in_reply_to场比赛的用户的ID

我的回购是在这里: https://github.com/paul-ylz/sample_app

0

我认为迈克尔·哈特尔的暗示了“在微柱添加in_reply_to列”是在比特你正在做的是复杂的事情扫描micropost内容。看看我的解决方案:

User_Controller方法包括:在饲料

#first of all, if you ever want to paginate an array, you need to include 
#'will_paginate/array', otherwise you'll experience problems. 
require 'will_paginate/array' 
def show 
    current_page = params[:page] 
    per_page = params[:per_page] 

    #creates an activity feed 
    @user = User.find(params[:id]) 
    @ears_burning = Array.new  #<<-- this is my @replies array 
    Micropost.all.each do |m| 
     #this looks for a username drop in the post, for example "greenranger" 
     if(m.content.include?(@user.username)) 
     #the micropost with the username(s) is added to the array 
     @ears_burning.push(m) 
     end 
    end 

    #my example app, users can also post blogs called "articles", hence 
    #the additional arrays, but it serves as a good example as to how I 
    #tackled the problem. As you can see, I merge them all into one array 
    @array = @user.microposts + @user.articles + @ears_burning 

    #This is the user profile activity array, sorted and paginated by 
    #created_at time. Simple! 
    @activity = @array.sort_by(&:created_at).reverse! 
    @pagination = @activity.paginate(page: params[:show], :per_page => 5) 

    # anything else that happens in show 
end 

我看起来有点凌乱@content,但它能够完成任务。你会注意到这只是寻找用户名,而不是@,所以这将只用于在微博中键入某人elses的用户名。我保持这种状态,因为社交网站如Twitter会自动包含用户的个人资料,无论名称前面是否有'@'符号,但通过使用我在下面的视图代码中使用的正则表达式,这可以稍微改变。

这样做的缺点是,如果用户有成千上万的链接的微博,那么您可能会注意到性能问题 - 但这种方法存在,就像数据库相关的性能问题一样。

要添加一个很好的“twitter”旋转事物,我在主页上的micropost源中添加了一个标记用户名链接。再一次,有很多方法可以做到这一点,但我认为最简单和最有效的方法是让_micropost部分逐字地构建每个微处理器,然后扫描每个“@”标记。微博有140个字符限制,所以它永远不会是一个巨大的工作。此代码将要去的地方你显示微观柱:

<!-- micropost main content --> 
<span class = "content"> 
    <% words = mp.content.split(" ") %> 
    <% words.each do |e| %> 
     <!-- this is where the magic happens, re-builds micropost --> 
     <% if e.include?("@") %> 
      <!-- adds a link to the user profile if '@' is detected --> 
      <%= link_to e, User.find_by_username(e[/@.*/].split('@')[+1][/[^ ]+/] 
         .delete(",")) %> <!-- that regex I was on about --> 
     <% else %> 
      <!-- posts the word in sequence if not a tag --> 
      <%= e %> 
     <% end %> 
     <!-- end of magic -->    
    <% end %> 
</span> 

这样做的缺点是,它带来一点逻辑到了Rails应用程序 - 的视图部分,但它在某些情况下是不可避免的。希望这可以帮助!