Bug in implemented tagging system

2020-05-06 08:59发布

问题:

I have followed Hartl's tutorial to make a ToDoList with a tagging system, also with the help of this word guide and video. However, I do not really understand how the tagging system works in terms of the filtering, so I just copied it and improvised.

Now I have a problem with my filtering system as now it just redirects to a brand new page that contains all tasks including those that doesn't have the clicked tag.

Before

After

Here is the updated log on my command line after inserting puts params.inspect in the MicropostsController#index, then clicking tag1 then tag2.

Started GET "/tags/tag1" for 127.0.0.1 at 2019-01-25 23:37:01 +0800
Processing by MicropostsController#index as HTML
  Parameters: {"tag"=>"tag1"}
  User Load (0.7ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  Tag Load (0.1ms)  SELECT  "tags".* FROM "tags" WHERE "tags"."name" = ? LIMIT ?  [["name", "tag1"], ["LIMIT", 1]]
<ActionController::Parameters {"controller"=>"microposts", "action"=>"index", "tag"=>"tag1"} permitted: false>
  Rendering microposts/index.html.erb within layouts/application
  Micropost Load (0.6ms)  SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" DESC  [["user_id", 2]]
  Tag Load (0.6ms)  SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."micropost_id" = ?  [["micropost_id", 20]]
  Tag Load (0.1ms)  SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."micropost_id" = ?  [["micropost_id", 14]]
  Tag Load (0.1ms)  SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."micropost_id" = ?  [["micropost_id", 8]]
  Tag Load (0.1ms)  SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."micropost_id" = ?  [["micropost_id", 2]]
  Rendered microposts/index.html.erb within layouts/application (15.8ms)
  Rendered layouts/_rails_default.html.erb (82.8ms)
  Rendered layouts/_shim.html.erb (0.3ms)
  Rendered layouts/_header.html.erb (1.2ms)
  Rendered layouts/_footer.html.erb (1.7ms)
Completed 200 OK in 157ms (Views: 116.8ms | ActiveRecord: 10.4ms)


Started GET "/tags/tag2" for 127.0.0.1 at 2019-01-25 23:37:16 +0800
Processing by MicropostsController#index as HTML
  Parameters: {"tag"=>"tag2"}
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  Tag Load (0.6ms)  SELECT  "tags".* FROM "tags" WHERE "tags"."name" = ? LIMIT ?  [["name", "tag2"], ["LIMIT", 1]]
<ActionController::Parameters {"controller"=>"microposts", "action"=>"index", "tag"=>"tag2"} permitted: false>
  Rendering microposts/index.html.erb within layouts/application
  Micropost Load (0.2ms)  SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" DESC  [["user_id", 2]]
  Tag Load (0.1ms)  SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."micropost_id" = ?  [["micropost_id", 20]]
  Tag Load (0.1ms)  SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."micropost_id" = ?  [["micropost_id", 14]]
  Tag Load (0.1ms)  SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."micropost_id" = ?  [["micropost_id", 8]]
  Tag Load (0.1ms)  SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."micropost_id" = ?  [["micropost_id", 2]]
  Rendered microposts/index.html.erb within layouts/application (9.6ms)
  Rendered layouts/_rails_default.html.erb (65.7ms)
  Rendered layouts/_shim.html.erb (0.3ms)
  Rendered layouts/_header.html.erb (1.1ms)
  Rendered layouts/_footer.html.erb (1.5ms)
Completed 200 OK in 104ms (Views: 95.9ms | ActiveRecord: 1.4ms)

Here's my controller code:

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]
  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 Micropost Page</h1>
<div class = "col-md-8 offset-2">
  <% @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>
    <% end %>
</div>

Micropost Model

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

Config/routes.rb and running rake routes

Rails.application.routes.draw do
  resources :users
  resources :microposts          

  get    '/about',   to: 'static_pages#about'
  get    '/contact', to: 'static_pages#contact'
  get    '/signup',  to: 'users#new'
  post    '/signup',  to: 'users#create'
  get    '/login',    to: 'sessions#new'
  post   '/login',    to: 'sessions#create'
  delete '/logout',   to: 'sessions#destroy'
  get   '/users/admin',     to: 'users#admin'

  get 'tags/:tag', to: 'microposts#index', as: :tag

  root   'static_pages#home'
end

        Prefix Verb   URI Pattern                    Controller#Action
         users GET    /users(.:format)               users#index
               POST   /users(.:format)               users#create
      new_user GET    /users/new(.:format)           users#new
     edit_user GET    /users/:id/edit(.:format)      users#edit
          user GET    /users/:id(.:format)           users#show
               PATCH  /users/:id(.:format)           users#update
               PUT    /users/:id(.:format)           users#update
               DELETE /users/:id(.:format)           users#destroy
    microposts GET    /microposts(.:format)          microposts#index
               POST   /microposts(.:format)          microposts#create
 new_micropost GET    /microposts/new(.:format)      microposts#new
edit_micropost GET    /microposts/:id/edit(.:format) microposts#edit
     micropost GET    /microposts/:id(.:format)      microposts#show
               PATCH  /microposts/:id(.:format)      microposts#update
               PUT    /microposts/:id(.:format)      microposts#update
               DELETE /microposts/:id(.:format)      microposts#destroy
         about GET    /about(.:format)               static_pages#about
       contact GET    /contact(.:format)             static_pages#contact
        signup GET    /signup(.:format)              users#new
               POST   /signup(.:format)              users#create
         login GET    /login(.:format)               sessions#new
               POST   /login(.:format)               sessions#create
        logout DELETE /logout(.:format)              sessions#destroy
   users_admin GET    /users/admin(.:format)         users#admin
           tag GET    /tags/:tag(.:format)           microposts#index
          root GET    /                              static_pages#home

Update:

It seems that running on rails console, the tagged_with method isn't filtering, comparing all microposts and what is supposed to be filtered by tagged_with.

irb(main):004:0> User.first.microposts
  User Load (0.3ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" DESC LIMIT ?  [["user_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Micropost id: 55, content: "Magnam nulla labore quibusdam veniam dolores.", user_id: 1, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 49, content: "Et non enim perspiciatis perferendis esse necessit...", user_id: 1, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 43, content: "Ducimus voluptatum esse qui iusto quasi magnam.", user_id: 1, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 37, content: "Adipisci iusto sed facilis molestiae.", user_id: 1, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 31, content: "Ipsam aliquid cum natus eos corrupti inventore.", user_id: 1, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 25, content: "Qui et non hic maiores et commodi laborum aut quib...", user_id: 1, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 19, content: "Itaque velit ut unde dolorem in.", user_id: 1, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 13, content: "Repellendus architecto rerum commodi dolorem.", user_id: 1, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 7, content: "Ut accusantium dolor voluptas quisquam laboriosam ...", user_id: 1, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 1, content: "Officiis non commodi at sit.", user_id: 1, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">]>
irb(main):005:0> User.first.microposts.tagged_with("tag2")
  User Load (0.3ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
  Tag Load (0.2ms)  SELECT  "tags".* FROM "tags" WHERE "tags"."name" = ? LIMIT ?  [["name", "tag2"], ["LIMIT", 1]]
  Micropost Load (0.5ms)  SELECT  "microposts".* FROM "microposts" INNER JOIN "taggings" ON "microposts"."id" = "taggings"."micropost_id" WHERE "taggings"."tag_id" = ? ORDER BY "microposts"."created_at" DESC LIMIT ?  [["tag_id", 4], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Micropost id: 57, content: "Magnam nulla labore quibusdam veniam dolores.", user_id: 3, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 54, content: "Et non enim perspiciatis perferendis esse necessit...", user_id: 6, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 51, content: "Et non enim perspiciatis perferendis esse necessit...", user_id: 3, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 49, content: "Et non enim perspiciatis perferendis esse necessit...", user_id: 1, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 48, content: "Ducimus voluptatum esse qui iusto quasi magnam.", user_id: 6, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 46, content: "Ducimus voluptatum esse qui iusto quasi magnam.", user_id: 4, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 45, content: "Ducimus voluptatum esse qui iusto quasi magnam.", user_id: 3, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 43, content: "Ducimus voluptatum esse qui iusto quasi magnam.", user_id: 1, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 42, content: "Adipisci iusto sed facilis molestiae.", user_id: 6, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, #<Micropost id: 40, content: "Adipisci iusto sed facilis molestiae.", user_id: 4, created_at: "2019-01-23 14:39:21", updated_at: "2019-01-23 14:39:21">, ...]>

Does anyone have any clue how the tagging system works and how to solve the problem? Do inform me if more information is needed. Thanks a lot in advance.

回答1:

If I understood correctly, when you click the particular tag in the list you supposed to be redirected to the page "Filtered Micropost Page" that contains all posts that include clicked tag.

From your view, microposts/index.html.erb you're sending user to tag_path so that's where all logic starts.

Based on ternary operator you hav on MicroPostController#index that means your params[:tag] is nil and you're listing all posts.

Could you please Stdout params.inspect

Cheers