实现了`tagged_with`方法,返回所有微博

时间:2019-01-27 09:49:55

标签: ruby-on-rails ruby activerecord

我已经按照Hartl的教程制作了带有标记系统的ToDoList,并且还借助了word guideRailsCast Tutorial。但是,我并不真正了解标记系统在过滤方面的工作方式,因此我只是复制并即兴创作了该标记系统。我最好的猜测是应该使用tagged_with方法,但是控制台测试似乎仍会显示所有微博。

我的过滤系统有问题,因为它现在重定向到一个全新的页面,其中包含所有任务,包括那些没有clicked标记的任务。单击tag2时,在我的本地计算机上完成了此实验。

之前 homepage

之后 wrong filter

这是发生的日志,我对日志有一些疑问,并在其中注释了

Started GET "/tags/try2" for 127.0.0.1 at 2019-01-27 17:33:53 +0800
Processing by MicropostsController#index as HTML
  Parameters: {"tag"=>"try2"}
  User Load (0.5ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 101], ["LIMIT", 1]]
  ↳ app/helpers/sessions_helper.rb:10
  Tag Load (0.3ms)  SELECT  "tags".* FROM "tags" WHERE "tags"."name" = $1 LIMIT $2  [["name", "try2"], ["LIMIT", 1]]
  ↳ app/models/micropost.rb:13

  Rendering microposts/index.html.erb within layouts/application
   (0.6ms)  SELECT COUNT(*) FROM "microposts" INNER JOIN "taggings" ON "microposts"."id" = "taggings"."micropost_id" WHERE "taggings"."tag_id" = $1  [["tag_id", 10]]
  ↳ app/views/microposts/index.html.erb:2

  Micropost Load (0.3ms)  SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = $1 ORDER BY "microposts"."created_at" DESC  [["user_id", 101]]
  ↳ app/views/microposts/index.html.erb:3

  Tag Load (0.3ms)  SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."micropost_id" = $1  [["micropost_id", 62]]
  ↳ app/views/microposts/index.html.erb:5

  ##The taggings.micropost_id = $1 for some reason here
  ##It's strange why the next even tag loads again for the 2nd time, when there are only 2 tags

  Tag Load (0.3ms)  SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."micropost_id" = $1  [["micropost_id", 61]]
  ↳ app/views/microposts/index.html.erb:5
  Rendered microposts/index.html.erb within layouts/application (7.1ms)
  Rendered layouts/_rails_default.html.erb (58.5ms)
  Rendered layouts/_shim.html.erb (0.3ms)
  Rendered layouts/_header.html.erb (0.8ms)
  Rendered layouts/_footer.html.erb (1.3ms)
Completed 200 OK in 96ms (Views: 84.1ms | ActiveRecord: 2.4ms)

这是我的控制器代码:

MicropostsController

class MicropostsController < ApplicationController
  before_action :logged_in_user, only: [:index, :show, :create, :destroy]
  before_action :correct_user,   only: :destroy

  def index
    @microposts = current_user.microposts
    @microposts = @microposts.tagged_with(params[:tag]) if params[:tag]
    @microposts = @microposts.paginate(page: params[:page])
  end

  def show
    @micropost = Micropost.find(params[:id])
  end


  def create
    @micropost = current_user.microposts.build(micropost_params)
    if @micropost.save
      flash[:success] = "Micropost created!"
      redirect_to root_url
    else
      @feed_items = []
      render 'static_pages/home'
    end
  end

  def destroy
    @micropost.destroy
    flash[:success] = "You have deleted a task!"
    redirect_to request.referrer || root_url
  end

  private

    def micropost_params
      params.require(:micropost).permit(:content, :tag_list, :tag, 
        {tag_ids: [] }, :tag_ids)
    end

    def correct_user
      @micropost = current_user.microposts.find_by(id: params[:id])
      redirect_to root_url if @micropost.nil?
    end
end

SessionsController

class SessionsController < ApplicationController

  def new
  end

  def create
    @user = User.find_by(email: params[:session][:email].downcase)
    if (@user && @user.authenticate(params[:session][:password]))
      log_in @user
      flash[:success] = "Welcome back, #{@user.name}!"
      params[:session][:remember_me] == '1' ? remember(@user) : forget(@user)
      redirect_back_or root_path
    else
      flash.now[:danger] = 'Invalid email/password combination'
      render 'new'
    end
  end

  def destroy
    log_out if logged_in?
    redirect_to root_url
  end
end

StaticPagesController

class StaticPagesController < ApplicationController
  def home
    if logged_in?
      @new_micropost = Micropost.new
      @feed_items = current_user.microposts.paginate(page: params[:page]) 
    end 
  end

  def help
  end

  def about
  end

  def contact
  end
end

UsersController

class UsersController < ApplicationController
  before_action :logged_in_user, only: [:edit, :update, :destroy]
  before_action :correct_user,   only: [:edit, :update]
  before_action :admin_user,     only: [:destroy]


  def show
    @user = User.find(params[:id])
    @microposts = @user.microposts.paginate(page: params[:page])
  end

  def new
    @user = User.new
  end

  def index
    @users = User.paginate(page: params[:page])
  end


  def create
   @user = User.new(user_params)
   if @user.save
     log_in @user
     flash[:info] = "Welcome to the to-do app, #{@user.name}"
     redirect_to @user
   else
     render 'new'
   end
  end

  def admin
    @users = User.paginate(page: params[:page])
  end

  def destroy
    a = User.find(params[:id]).name
    User.find(params[:id]).destroy
    flash[:success] = "#{a} has been deleted!"
    redirect_to users_url
  end

  def admin_user
    redirect_to(root_url) unless current_user.admin?
  end

 def edit
   @user = User.find(params[:id])
 end

 def update
  @user = User.find(params[:id])
  if @user.update_attributes(user_params)
    flash[:success] = "Profile for @user.name has been updated"
    redirect_to(@user)
  else
    flash[:danger] = "Update Failed."
    render 'edit'
  end
end

  private
    def user_params
      params.require(:user).permit(:name, :email, :password,
                                  :password_confirmation, :admin)
    end
    def logged_in_user
      unless logged_in?
        store_location
        flash[:danger] = "You are not logged in. Please log in."
        redirect_to login_url
      end
    end

    def correct_user
      @user = User.find(params[:id])
      if !current_user?(@user)
        flash[:danger] = "You are not authorized to visit this page."
        redirect_to(root_url)
      end
    end
  end

microposts / index.html.erb

<h1>Filtered Tasks</h1>
<%= will_paginate %>
  <% @current_user.microposts.each do |micropost| %>
    <p><%= truncate(micropost.content, length: 50) %></p>
    <p><small>Tags: <%= raw micropost.tags.map(&:name).map { |t| link_to t, tag_path(t) }.join(', ') %></small></p>
        <span class="timestamp">
            Posted <%= time_ago_in_words(micropost.created_at) %> ago.
            <% if current_user?(micropost.user) %>
              <%= link_to "Done", micropost_path(micropost), method: :delete, data: { confirm: "Keep up the good work!" } %>
            <% end %>
        </span>
        <br><br>
    <% end %>
<%= will_paginate %>

Micropost模型

class Micropost < ApplicationRecord
  belongs_to :user
  has_many :taggings
  has_many :tags, through: :taggings, :dependent => :delete_all
  default_scope -> { order(created_at: :desc) }
  validates :user_id, presence: true
  validates :content, presence: true, length: {maximum: 140 }
  attr_accessor :tag_list



  def self.tagged_with(name)
    Tag.find_by!(name: name).microposts
  end

  def self.tag_counts
    Tag.select('tags.*, count(taggings.tag_id) as count')
    .joins(:taggings).group('taggings.tag_id')
  end

  def tag_list
    tags.map(&:name).join(', ')
  end

  def tag_list=(names)
    self.tags = names.split(',').map do |n|
      Tag.where(name: n.strip).first_or_create!
    end
  end
end

有人知道标签系统如何工作,尤其是tagged_with为什么返回所有微帖子?如果需要更多信息,请告诉我。提前谢谢。

1 个答案:

答案 0 :(得分:0)

我建议您使用适当的标记宝石,而不要手工实施,检查行为是否可标记,它已经具有tagged_with方法https://github.com/mbleigh/acts-as-taggable-on/blob/0082724158e2f80ddbce095a97afd990a004bf26/lib/acts_as_taggable_on/taggable/core.rb#L103,并且您将少很多头痛。我猜这颗宝石是围绕该栏杆建造的,而该栏杆是旧的,仅是该示例的限制,该宝石具有更多功能。

问题是您的tagged_with方法不关心先前的作用域,您是使用Tag类方法将其丢弃,而不是使用当前作用域来构建请求。

def self.tagged_with(name)
  Tag.find_by!(name: name).microposts
end

ActsAsTaggableOn可以正确处理此问题。