Rails 3:用户对实体的多态喜好,怎么样?

Sch*_*ann 5 ruby ruby-on-rails ruby-on-rails-3

背景:

我按照这里的教程在我的应用程序中设置了多态用户收藏夹数据模型.这让我可以让用户在系统中创建几乎任何实体,我has_many :favorites, :as => :favorable在其模型中添加了一个最喜欢的实体.我计划使用它来实现Facebook风格的"Like"系统以及其他几个类似的系统.

首先,我将优先级添加到Post模型(每个用户都可以在Facebook上创建状态更新).我完成了所有这些工作并进行了单元测试,因此我知道数据模型在关系的任何一方(User和Post)都是健全的.

细节:

  • 我有一个带有单索引方法和视图的Home控制器.

  • 在索引视图中,我为用户和用户的朋友渲染了帖子

  • 我希望用户能够喜欢他们朋友的帖子

  • Posts控制器只有一个创建和一个带有相关路由的destroy方法(不是一个完整的成熟资源),并且通过AJAX帖子通过Post方法创建和删除没有问题

我被卡住了

  • 如何添加链接或按钮以将帖子添加到用户的收藏夹?

  • 根据教程,通过多态关联创建新收藏夹的方法是从Post.favorites.build(:user_id => current_user.id)中完成.从这个方向构建处理拉出Post的ID和TYPE,我所要做的就是传递用户的id

  • 我是否使用类似于Post控制器的Create and Destroy方法将AJAX表单发布到收藏夹控制器?

  • 从ASP.Net N-Tier Web应用程序开发到Rails MVC,我仍然在努力解决大脑中的电线问题.直到现在还没太糟糕;)

  • 我打赌那里有宝石可能会这样做,但我需要学习,最好的办法就是忍受它.也许来自在其应用程序中实现了喜欢功能的人的教程或示例代码会有所帮助.

在此先感谢您的帮助!

Sch*_*ann 5

Jaap,感谢您对我的问题发表的评论。写下问题后,我几乎不想等待,因为真正的学习是通过反复试验进行的,所以我把它弄错了;)

事实证明,您的建议与我最终自己做的事情几乎是一致的(很高兴发现您决定要做的就是别人也会做,我很喜欢所有这些的理智检查价值)。

所以这就是我所做的,并且所有工作都通过回发进行。现在,我只需要实现AJAX并设置其样式:

我最喜欢的模型,因为我的多态收藏夹模型要求一个实体只能被添加到验证“范围”的用户收藏一次,这表明对于每个属性,该实体在其他2个必需属性的范围内必须是唯一的。这解决了同一用户存在多个收藏夹的问题。

class Favorite < ActiveRecord::Base
  before_save :associate_user

  belongs_to :favorable
  belongs_to :user

  # Validations
  validates :user_id, :presence => true,
            :uniqueness => {:scope => [:favorable_id, :favorable_type], :message => "item is already in favorites list."}
  validates :favorable_id, :presence => true,
            :uniqueness => {:scope => [:user_id, :favorable_type], :message => "item is already in favorites list."}
  validates :favorable_type, :presence => true,
            :uniqueness => {:scope => [:favorable_id, :user_id], :message => "item is already in favorites list."}

  # Callbacks
  protected

  def associate_user
    unless self.user_id
      return self.user_id = session[:user_id] if session[:user_id]
      return false
    end
  end

end
Run Code Online (Sandbox Code Playgroud)

我的用户模型(相关的用户模型):我添加了2种方法,get_favorites与本教程中的推荐方法相同,而Favorite?检查该实体是否已添加到用户的收藏夹中的方法。

class User < ActiveRecord::Base  
  # Relationships
  has_many  :microposts, :dependent => :destroy
  has_many  :favorites

  # Methods
  def favorite?(id, type)
    if get_favorites({:id => id, :type => type}).length > 0
      return true
    end
    return false
  end

  def get_favorites(opts={})
    # Polymorphic Favoritability: allows any model in the
    # application to be favorited by the user.
    # favorable_type
    type = opts[:type] ? opts[:type] : :topic
    type = type.to_s.capitalize

    # add favorable_id to condition if id is provided
    con = ["user_id = ? AND favorable_type = ?", self.id, type]

    # append favorable id to the query if an :id is passed as an option into the
    # function, and then append that id as a string to the "con" Array
    if opts[:id]
      con[0] += " AND favorable_id = ?"
      con << opts[:id].to_s
    end

    # Return all Favorite objects matching the above conditions
    favs = Favorite.all(:conditions => con)

    case opts[:delve]
    when nil, false, :false
      return favs
    when true, :true
      # get a list of all favorited object ids
      fav_ids = favs.collect{|f| f.favorable_id.to_s}

      if fav_ids.size > 0
        # turn the Capitalized favorable_type into an actual class Constant
        type_class = type.constantize

        # build a query that only selects
        query = []
        fav_ids.size.times do
          query << "id = ?"
        end
        type_conditions = [query.join(" AND ")] + fav_ids

        return type_class.all(:conditions => type_conditions)
      else
        return []
      end
    end
  end

end
Run Code Online (Sandbox Code Playgroud)

我的Micropost模型(相关的模型):请注意has_many关系中名为:favorites的多态关联。

class Micropost < ActiveRecord::Base
  attr_accessible :content

  # Scopes
  default_scope :order => 'microposts.created_at DESC'

  # Relationships
  belongs_to  :user
  has_many  :favorites, :as => :favorable # Polymorphic Association

  # Validations
  validates :content, :presence => true, :length => { :minimum => 1, :maximum => 140 }
  validates :user_id, :presence => true

end
Run Code Online (Sandbox Code Playgroud)

我的Micropost表单:如您所见,我正在将要映射到Favorite模型的实体作为本地变量传递给2种Favorite表单,称为“ local_entity”。这样,我可以为多态关联提取实体的ID和类型。

<div class="post">
    <span class="value">
      <%= micropost.content %>
    </span>
    <span>
        <% if current_user.favorite?(micropost.id, micropost.class.to_s) %>
            <%= render :partial => 'favorites/remove_favorite', :locals => {:local_entity => micropost} %>
        <% else %>
            <%= render :partial => 'favorites/make_favorite', :locals => {:local_entity => micropost} %>
        <% end %>
    </span>
    <span class="timestamp">
        Posted <%= time_ago_in_words(micropost.created_at) %> ago.
    </span>
    <div class="clear"></div>
</div>
Run Code Online (Sandbox Code Playgroud)

我的最爱表格:

<%= form_for current_user.favorites.build do |f| %>
    <div><%= f.hidden_field :favorable_id, :value => local_entity.id %></div>
    <div><%= f.hidden_field :favorable_type, :value => local_entity.class.to_s %></div>
    <div class="actions"><%= f.submit "make favorite" %></div>
<% end %>
Run Code Online (Sandbox Code Playgroud)

我的删除收藏夹表格:

<%= form_for current_user.get_favorites(
                     {:id => local_entity.id,
                      :type => local_entity.class.to_s}),
                      :html => { :method => :delete } do |f| %>
    <div class="actions"><%= f.submit "remove favorite" %></div>
<% end %>
Run Code Online (Sandbox Code Playgroud)