Rails用户has_many帖子,has_many favorite_posts

时间:2018-03-15 12:23:30

标签: ruby-on-rails associations

首先抱歉英语

所以我已经有了“用户 - 帖子”一对多关联,这意味着每个帖子只能有一位作者,现在我想在用户个人资料中添加“收藏帖子”按钮,并“添加到收藏夹”按钮每个帖子,所以问题是如何实现这种正确的方式?我应该重写我的用户 - 帖子关联? 还是创造另一种模式?我有点困惑。提前谢谢!

其实我想要这个结果:

@ user.posts #retret此用户创建的所有帖子

@ user.favorite_posts #return此用户添加到收藏夹的帖子

这是我的用户模型:

class User < ApplicationRecord

  mount_uploader :avatar, ImageUploader
  validates :username, presence: true, uniqueness: true, length: {in: 3..20}

  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :validatable

  has_many :posts, dependent: :destroy
  has_many :comments, dependent: :destroy
  has_many :ratings
  enum role: [ :user, :admin ]

  def calculate_average
    ratings.blank? ? 0 : ratings.map(&:value).inject(:+) / ratings.count.to_f
  end
end

发布模型:

class Post < ApplicationRecord
  mount_uploader :image, ImageUploader
  validates :body, presence: true
  validates :title, presence: true, length: { maximum: 50}

  belongs_to :user
  has_many :comments, dependent: :destroy
end

修改

好吧,看看我是怎么做到的,它的工作原理与我想要的完全一样。

以下是我的用户模型:

class User < ApplicationRecord

  mount_uploader :avatar, ImageUploader
  validates :username, presence: true, uniqueness: true, length: {in: 3..20}

  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :validatable

  has_many :posts, dependent: :destroy
  has_many :comments, dependent: :destroy
  has_many :ratings
  has_many :favorites, dependent: :destroy
  has_many :favorite_posts, through: :favorites, source: "post"
  enum role: [ :user, :admin ]

  def calculate_average
    ratings.blank? ? 0 : ratings.map(&:value).inject(:+) / ratings.count.to_f
  end
end

3 个答案:

答案 0 :(得分:4)

您最喜欢的帖子需要many-to-many个关系,首先运行此命令以创建表格favorite_posts

rails g model FavoritePost user:references post:references

然后

rails db:migrate

然后将这些添加到您的模型中将如下所示:

#=> model/user.rb
class User < ApplicationRecord
    has_many :favorite_posts, dependent: :destroy # or you can use only this line except second if you will face any problem
    has_many :posts, through: :favorite_posts
end

#=> model/post.rb
class Post < ApplicationRecord
    has_many :favorite_posts, dependent: :destroy
    has_many :users, through: :favorite_posts
end

#=> model/favorite_post.rb
class FavoritePost < ApplicationRecord
  belongs_to :user
  belongs_to :post
end

这是关系部分,现在创建一个最喜欢的帖子部分。对于新代码,您可以创建一个控制器,即

rails g controller favorites

然后你的路线档案:

resources :favorites

使用rake routes的新路线示例:

    favorites GET    /favorites(.:format)          favorites#index
              POST   /favorites(.:format)          favorites#create
 new_favorite GET    /favorites/new(.:format)      favorites#new
edit_favorite GET    /favorites/:id/edit(.:format) favorites#edit
     favorite GET    /favorites/:id(.:format)      favorites#show
              PATCH  /favorites/:id(.:format)      favorites#update
              PUT    /favorites/:id(.:format)      favorites#update
              DELETE /favorites/:id(.:format)      favorites#destroy

在您的视图文件中添加以下内容:

# For creating favorite
<%= link_to "Favorite", favorites_path(user: current_user, post: post.id), class: 'btn bf-save-btn', method: :post, data: {disable_with: "Saving..."}, title: "Add to favorite" %>

# For deleting favorite list
<%= link_to "Unfavorite", favorite_path(post.id), class: 'btn af-save-btn', method: :delete, data: {disable_with: "Removing...."}, title: "Remove from favorite" %>

favorites_controller.rb

def index
    @saves = current_user.favorite_post
end
# index.html.erb
<% @saves.each do |fav| %>
     <%= link_to fav.post.post_title, post_path(fav.post) %>
<% end %>

def create
    @save = FavoritePost.new(post_id: params[:post], user: current_user)

    respond_to do |format|
        if @save.save
            flash[:success] = 'Saved'
            format.html { redirect_to request.referer }
            format.xml  { render :xml => @save, :status => :created, :location => @save }
        else
            format.html { redirect_to request.referer }
            format.xml  { render :xml => @save.errors, :status => :unprocessable_entity }
        end
    end
end

def destroy
    post = Post.find(params[:id])
    @save = FavoritePost.where(user_id: current_user.id, post_id: post.id).first

    respond_to do |format|
        if @save.destroy
            flash[:error] = 'Unsaved'
            format.html { redirect_to request.referer, status: 303  }
            format.js { redirect_to request.referer, status: 303  }
            # format.xml  { head :ok }
        end
    end
end

这是喜欢/不喜欢的功能。现在,您需要为何时显示Favorite和何时Unfavorite创建一些逻辑。

对于这个要求有很多方法,首先你需要了解这一点,然后你可以随心所欲。

另外,要在不重新加载页面的情况下实现此目的,您可以尝试一些Ajax

<强>更新

class User < ApplicationRecord

    mount_uploader :avatar, ImageUploader
    validates :username, presence: true, uniqueness: true, length: {in: 3..20}

    devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :validatable

    has_many :posts, dependent: :destroy
    has_many :comments, dependent: :destroy
    has_many :ratings

    # Newly added
    has_many :favorite_posts, dependent: :destroy # or you can use only this line except second if you will face any problem
    has_many :posts, through: :favorite_posts

    enum role: [ :user, :admin ]

    def calculate_average
        ratings.blank? ? 0 : ratings.map(&:value).inject(:+) / ratings.count.to_f
    end
end

希望它会有所帮助。

答案 1 :(得分:1)

fool-dev的答案不提供对收藏帖子的直接访问,因此索引视图需要循环。 Prasanna的方法解决了这个问题,但他的答案被不公平地指责为不完整和抄袭:-)。所以这是完整的方法:

您需要多对多关系,这是正确的,因此您需要一个连接模型和表。但这个模型是辅助的。没有重要的逻辑,我认为它不值得控制者或观点。

class User < ApplicationRecord
  has_many :posts, dependent: :destroy # Posts created by this user
  has_many :favs, dependent: :destroy  
  has_many :fav_posts, through: :favs # Favorite posts for this user
end

class Post < ApplicationRecord
  belongs_to :user
  has_many :favs, dependent: :destroy
  has_many :fav_users, through: :favs # Users who have this post as favorite
end

class Fav < ApplicationRecord
  belongs_to :user
  belongs_to :post
end

这允许使用用户类中的两种不同方法访问用户创建的所有帖子以及他喜欢的所有帖子。

@posts = current_user.posts         # Posts created by this user
@fav_posts = current_user.fav_posts # Favorite posts 

在视图中:

<h1><% current_user.name %></h1>
<h2>Your posts</h2>
<%= render @posts %>
<h2>Your favorite posts from other users</h2>
<%= render @fav_posts %>

您无需控制器即可创建,查看或删除收藏的帖子。只需在User或Post控制器中处理此逻辑即可。例如,要收藏或不喜欢帖子,只需在PostsController中添加fav和unfav方法。

def fav
  current_user.fav_posts << Post.find(params[:id])
end

def unfav
  current_user.favs_posts.destroy(Post.find(params[:id]))
end

在视图中:

<%= link_to "Favorite", fav_post_path(id: post.id) %>
<%= link_to "Unfavorite", unfav_post_path(id: post.id) %>

您应该在路线中添加以下方法:

post '/posts/:id/fav', to: 'posts#fav', as: 'fav_post'    
post '/posts/:id/unfav', to: 'posts#unfav', as: 'unfav_post'

答案 2 :(得分:0)

为&#39; UserFavoritePost&#39;创建新模型存储了post_id和user_id。并为favorite_posts创建自定义关联

class UserFavoritePost < ApplicationRecord
  belongs_to :post    
  belongs_to :user
end

class User < ApplicationRecord
  has_many :posts, dependent: :destroy
  has_many :user_favorite_posts
  has_many :favorite_posts, throught: :user_favorite_posts, class: 'Post'

end