【问题标题】:Ruby Rails Sort Index List of users by most recent reviewRuby Rails 排序索引 用户最近评论列表
【发布时间】:2021-04-26 18:51:57
【问题描述】:

我有一个发表评论的用户列表。我正在尝试使列表以不同的方式排序。我坚持按每个用户的最新评论对列表进行排序。

我目前的方法是制作模型范围。我就是不明白。

这是模型:

class User < ApplicationRecord
  attr_accessor :password
  validates_confirmation_of :password
  validates :email, :presence => true, :uniqueness => true
  validates :user_name, :presence => true, :uniqueness => true
  before_save :encrypt_password
  
  has_many :reviews
  has_one_attached :avatar_pic


  scope :users_most_recent, -> {(
    select('users.id, users.user_name')
    .joins(:reviews).where('reviews.updated_at')
    .group('users.id')
    .order('updated_at DESC')
    )}


  def self.user_reviews(user_id)
    @user_reviews = Review.where(user_id: user_id).count
  end

  def self.user_ave_rating(user_id)
    _average_reviews = []
    _rev_count = 0
    _new_average = 0.0
    _average_reviews = Review.where(user_id: user_id)
    _average_reviews.each do |average_review|
      _rev_count += average_review.rating
    end
    _new_average = (_rev_count / _average_reviews.length.to_f).round(1)
  end

  def self.user_latest_review(user_id)
    @latest_review = Review.where(user_id: user_id).where('created_at < ? ', Time.now).order('created_at DESC').first
    if @latest_review.nil?
      last_review = {}
      else
        last_review = @latest_review.created_at.strftime('%m-%d-%Y')
    end
  end

  def encrypt_password
    self.password_salt = BCrypt::Engine.generate_salt
    self.password_hash = BCrypt::Engine.hash_secret(password,password_salt)
  end

  def self.authenticate(email, password)
    user = User.find_by "email = ?", email
    if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
      user
    else
      nil
    end
  end

end

这是控制器,索引是我要实现的地方:

class UsersController < ApplicationController
  before_action :current_user, only: [:show, :edit, :update, :destroy]
  
  def new
    @user = User.new
  end
  
  def create
    @user = User.new(user_params)
    @user.avatar_pic.attach(params[:user][:avatar_pic])
    if @user.save
      flash[:notice] = "You've successfully signed up!"
      session[:user_id] = @user.id
      redirect_to "/"
    else
      flash[:alert] = "There was a problem signing up."
      redirect_to '/signup'
    end
  end

  def show
    @user = current_user
    render :show
  end  

  def edit
    @user = current_user
    render :edit
  end  

  def update
    @user = current_user

    if @user.update(user_params)
      flash[:notice] = "Profile successfully updated!"
      redirect_to user_path(@user)
    else
      render :edit
      flash[:notice] = "Something went wrong. Please contact Mario's technical assistance staff."
    end
  end

  def index
    case
    when params[:az]
      @users = User.order('user_name').paginate(page: params[:page], per_page: 20)
    when params[:za]
      @users = User.order('user_name DESC').paginate(page: params[:page], per_page: 20)
    when params[:high_rating]
      "High Rating"
    when params[:low_rating]
      "Low Rating"
    when params[:most_reviews]
      "Most Reviews"
    when params[:least_reviews]
      "Least Reviews"
    when params[:most_recent]
      @users = User.users_most_recent.paginate(page: params[:page], per_page: 20)
    when params[:least_recent]
      "Least Recent"
    else
      @users = User.all.paginate(page: params[:page], per_page: 20)
    end
    render :index
  end
  
  

  private
  
  def user_params
    params.require(:user).permit(:email, :user_name, :password, :password_confirmation, :admin, :avatar_pic)
  end
end

这是我的看法:

<p id="notice"><%= notice %></p>

<div class="sort-flex-wrapper">
  <h1 class="center">Our Community</h1>

  <div class="btn-group sort-button">
    <button type="button" class="btn btn-outline-secondary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
      Sort By
    </button>
    <div class="dropdown-menu">

      <%= link_to "User Name A-Z", users_path(:az => 'az'), class: "dropdown-item" %>
      <%= link_to "User Name Z-A", users_path(:za => 'za'), class: "dropdown-item" %>
      <%= link_to "Highest Average Rating", users_path(:high_rating => 'high_rating'), class: "dropdown-item" %>
      <%= link_to "Lowest Average Rating", users_path(:low_rating => 'low_rating'), class: "dropdown-item" %>
      <%= link_to "Most Reviews", users_path(:most_reviews => 'most_reviews'), class: "dropdown-item" %>
      <%= link_to "Least Reviews", users_path(:least_reviews => 'least_reviews'), class: "dropdown-item" %>
      <%= link_to "Most Recent Review", users_path(:most_recent => 'most_recent'), class: "dropdown-item" %>
      <%= link_to "Least Recent Review", users_path(:least_recent => 'least_recent'), class: "dropdown-item" %>

    </div>
  </div>
</div>

<div class="community-flex-container">
  <% if @users.any? %>
    <% @users.each do |user| %>

      <div class="community-profile-card">
        <div class="community-profile-flex">

          <div class="community-profile-box1">
            <% if user.avatar_pic.attached? %>
              <%= image_tag user.avatar_pic, class:"avatar" %><br>
              <% else %>
                <%= image_tag 'generc_profile_pic.webp', class:"avatar", alt: 'Avatar Not Found ' %><br>
            <% end %>
          </div>

          <div class="community-profile-box2">
            <div class="community-column-box1">
              <% if user.user_name? %>
                <h3><%= user.user_name %></h3>
                <% else %>
                <h3>Guest User</h3>
              <% end %>
            </div>

            <div class="community-column-box2">
              <div class="community-align-stars"> 
                <p>Average Rating: </p>              
              </div>
              <div class="community-align-stars">
                <div class="star-align">
                  <%= render partial: "shared/review_stars", locals: { review: User.user_ave_rating(user.id) } %>
                </div>
              </div>                  
            </div>

            <div class="community-column-box3">
              <p>Number of Reviews: <%= User.user_reviews(user.id) %></p>
            </div>

            <div class="community-column-box4">
              <% if User.user_latest_review(user.id) == {} %>
                <p>Most Recent Review: None</p>
                <% else %>
                  <p>Most Recent Review: <%= User.user_latest_review(user.id) %></p>
              <% end %>
            </div>
            
          </div>
        </div>
      </div> 

    <% end %>

  <% else %>
    <p>There are no users (yet).</p>
  <% end %>
</div>
<div class="pagination">
  <%= will_paginate @reviews%>
</div>

【问题讨论】:

  • 那么你所做的事情有什么不妥?
  • 目前,我收到一条消息崩溃:ActiveRecord::StatementInvalid in Users#index PG::DatatypeMismatch: ERROR: argument of WHERE must be type boolean, not type timestamp without time zone LINE 1: ...ews" ON "reviews"."user_id" = "users"."id" WHERE (reviews.up...
  • 是的,您的查询中的位置没有意义,我在回答中将其删除。去哪里的目的是什么?
  • 我有点过头了。这是一种失败的方法。
  • 不用担心。我希望它现在可以工作

标签: ruby-on-rails ruby


【解决方案1】:
scope :users_most_recent, -> {(
    select('users.id, users.user_name, max(reviews.updated_at) as reviews_updated_at')
    .joins(:reviews)
    .group('users.id')
    .order('reviews_updated_at')
    )}

【讨论】:

  • 谢谢乔尔!它现在没有崩溃(耶!),但日期不按顺序。
  • 是的,所以我要添加 .order。我想你解决了我的问题
  • 嗯,他们应该已经在最新评论中订购了......
  • 是的,我弄乱了命令并没有帮助我。大多数日期来自数据库种子。但是我为某些用户手动进行了一些评论,并且它们没有按任何顺序显示。有你想看的文件吗?我忽略了什么?
  • 用户应该点什么?根据每个用户所做的最新评论。那么你到底看到了什么,用户不是根据最新评论排序的吗?
【解决方案2】:

好吧,虽然我们这样做了,但我们不妨修复整个索引方法。您在控制器中做了很多事情,将其拆分为如下内容:

class UserList
  def self.order_users_by(order_value)
    case order_value
    when :az
      User.order('user_name ASC')
    when :za
      User.order('user_name DESC')
    when :high_rating
      User.all.sort_by(&:average_rating).reverse
    when :low_rating
      User.all.sort_by(&:average_rating)
    when :most_reviews
      User.all.sort_by(&:review_count).reverse
    when :least_reviews
      User.all.sort_by(&:review_count)
    else
      User.all.sort_by(&:last_updated_review)
    end
  end
end

class User   
  def average_rating
    (BigDecimal(reviews.sum(:rating).to_s) / BigDecimal(reviews.count.to_s)).round(1)
  end

  def review_count
    reviews.count
  end

  def last_updated_review
    reviews.order("updated_at")
  end
end

class UsersController < ApplicationController
  def index
    UserList.order_users_by(params).paginate(page: params[:page], per_page: 20)
  end
end

【讨论】:

  • 这实际上解决了我必须解决的几件事。谢谢!
  • 如果您不介意,我有几个问题。我查了BigDecimal,很有趣。为什么 to_s 那些?
  • 很高兴为您提供帮助。因为 BigDecimals 只接受字符串,所以它确保当您使用十进制值进行计算时,答案是精确的。你永远不应该用浮点值计算,答案是不准确的。你可以通过谷歌搜索或阅读这里dzone.com/articles/…
  • 我一直使用@users 和渲染索引。这个新的 User 类如何与其他 Rails CRUD 功能不冲突。像 User.new 一样用于 Create 方法?
  • Nono,User 类与具有活动记录的用户模型相同。我刚刚草草了我要添加的方法。
猜你喜欢
  • 2015-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-20
  • 2011-04-29
  • 2013-06-04
相关资源
最近更新 更多