【问题标题】:Ordering by category id and price on index page在索引页面上按类别 ID 和价格排序
【发布时间】:2021-02-03 19:54:27
【问题描述】:

我在订购房屋时遇到了麻烦。我有一个属于类别的房屋(类别 has_many 房屋),我想根据他们的 category_id 对索引中的房屋进行排序,但无论我尝试什么似乎都不会改变顺序。这对我来说是个谜。或许你能帮帮我?

class HousesController < ApplicationController
  skip_before_action :authenticate_user!, only: [:index, :show]
  before_action :set_house, only: [ :show, :edit, :update, :destroy, :inquiry ]
​
  def index
    # byebug
    @houses = policy_scope(House).order(:name)
    @houses = params.has_key?(:h) ? index_result(@houses) : @houses
    # split_categories(@houses)
  end
​
  def index_result(houses)
    # byebug
    wall_thickness = params[:h].to_i
    if wall_thickness == 1
      houses.order(:name)
      render "results_index_all"
    elsif wall_thickness == 28 || 40
      houses = houses.where(:wall => wall_thickness)
      houses.order(:name)
      render "results_index"
    else
    end
  end
​
  def split_categories(houses)
    # @houses_1 = @houses.where(price_cents: 0...260000)
    # @houses_2 = @houses.where(price_cents: 260000..1000000)
    # byebug
    category = Category.find_by(id: params[:category])
    houses = @category.present? ? category.houses.order(price_cents: :asc) : houses
  end
​
  def show
  end
​
  def new
    @house = House.new
    authorize @house
  end
​
  def create
    @house = House.new(house_params)
    @house.user = current_user
    authorize @house
    if @house.save
      redirect_to house_path(@house)
    else
      render :new
    end
  end
​
  def edit
  end
​
  def update
    if @house.update(house_params)
      redirect_to house_path(@house)
    else
      render :edit
    end
  end
​
  def destroy
    @house.destroy
    redirect_to root_path
  end
​
  private
​
  def set_house
    @house = House.friendly.find(params[:id])
    authorize @house
  end
​
  def house_params
    params.require(:house).permit(:sku, :name, :price_cents, :width, :length, :wall, pictures: [])
  end
​
end

以下是正常索引,我将房屋分为从 category_id 开始的类别:2(普通花园房屋),然后是 1(凉亭),最后是 3(车库)。这是部分呈现 app/views/houses/index.html.erb

<% if !@category %>
<%= render 'first-banner-home' %>
  <div class="container catalog">
    <%= render "filter_buttons" %>
    <div class="row">
      <% @houses.where(category_id: 2).each do |house| %>
      <div class="col-sm-6 col-md-4">
        <div class="card">
          <% if house.pictures? %>
            <div class="imageTop" style="position: relative;">
              <%= cl_image_tag(house.pictures[0], :quality=>50, :width=>1800, :crop=>"scale", class: "card-img-top", alt: house.name + " " + house.category.name) %>
              <%= link_to "", house_path(house), class: "card-link" %>
            </div>
          <% end %>
          <div class="card-body indexBody">
            <div class="card-price">
              <h3 class="card-title"><%= house.name %></h3>
              <h3><%= house.length.to_f / 100 %> x <%= house.width.to_f.to_f / 100 %> m</h3>
            </div>
            <div class="card-price">
            <% if house.price_present == false %>
                <h3><%= t('show.consult') %></h3>
            <% else %>
                <h3><%= humanized_money_with_symbol(house.original_price) %><span style="color: red"> - 15%</span> = <%= humanized_money_with_symbol(house.price) %></h3>
              <% end %>
            </div>
            <% if policy(house).update? %>
              <%= link_to "Edit", edit_house_path(house) %>
            <% end %>
            <% if policy(house).destroy? %>
              <%= link_to "Remove", house_path(house), method: :delete, data: { confirm: "Are you sure?" } %>
            <% end %>
          </div>
        </div>
      </div>
      <% end %>
    </div>
  </div>
  <div class="container catalog">
    <h3><%= t('home.gazebos') %></h3>
    <div class="row">
      <% @houses.where(category_id: 1).each do |house| %>
      <div class="col-sm-6">
        <div class="card">
          <% if house.pictures? %>
            <div class="imageTop" style="position: relative;">
              <%= cl_image_tag(house.pictures[0], :quality=>50, :width=>1800, :crop=>"scale", class: "card-img-top-alt", alt: house.name + " " + house.category.name) %>
              <%= link_to "", house_path(house), class: "card-link" %>
            </div>
          <% end %>
          <div class="card-body indexBody">
            <div class="card-price">
              <h3 class="card-title"><%= house.name %></h3>
              <h3><%= house.length.to_f / 100 %> x <%= house.width.to_f.to_f / 100 %> m</h3>
            </div>
            <div class="card-price">
            <% if house.price_present == false %>
                <h3><%= t('show.consult') %></h3>
            <% else %>
                <h3><%= humanized_money_with_symbol(house.original_price) %><span style="color: red"> - 15%</span> = <%= humanized_money_with_symbol(house.price) %></h3>
              <% end %>
            </div>
            <% if policy(house).update? %>
              <%= link_to "Edit", edit_house_path(house) %>
            <% end %>
            <% if policy(house).destroy? %>
              <%= link_to "Remove", house_path(house), method: :delete, data: { confirm: "Are you sure?" } %>
            <% end %>
          </div>
        </div>
      </div>
      <% end %>
    </div>
  </div>
  <div class="container catalog">
    <h3><%= t('home.garages') %></h3>
    <div class="row">
      <% @houses.where(category_id: 3).each do |house| %>
      <div class="col-sm-6">
        <div class="card">
          <% if house.pictures? %>
            <div class="imageTop" style="position: relative;">
              <%= cl_image_tag(house.pictures[0], :quality=>50, :width=>1800, :crop=>"scale", class: "card-img-top-alt", alt: house.name + " " + house.category.name) %>
              <%= link_to "", house_path(house), class: "card-link" %>
            </div>
          <% end %>
          <div class="card-body indexBody">
            <div class="card-price">
              <h3 class="card-title"><%= house.name %></h3>
              <h3><%= house.length.to_f / 100 %> x <%= house.width.to_f.to_f / 100 %> m</h3>
            </div>
            <div class="card-price">
            <% if house.price_present == false %>
                <h3><%= t('show.consult') %></h3>
            <% else %>
                <h3><%= humanized_money_with_symbol(house.original_price) %><span style="color: red"> - 15%</span> = <%= humanized_money_with_symbol(house.price) %></h3>
              <% end %>
            </div>
            <% if policy(house).update? %>
              <%= link_to "Edit", edit_house_path(house) %>
            <% end %>
            <% if policy(house).destroy? %>
              <%= link_to "Remove", house_path(house), method: :delete, data: { confirm: "Are you sure?" } %>
            <% end %>
          </div>
        </div>
      </div>
      <% end %>
    </div>
  </div>
  <%= render "last-banner" %>
<% elsif params[:h].present? %>
  <%= render "results_index" %>
<% else %>
  <%= render "category_index" %>
<% end %>

这是根据墙壁厚度过滤房屋的索引(参见 app/controllers/houses_controller.rb )。这是我希望房子根据他们的 category_id 订购的地方,目前这不起作用。

<% content_for(:title) do %><%= t('topbar.brand') %><% end %>
<% content_for(:og_site_name) do %><%= t('topbar.brand') %><% end %>
<% content_for(:description) do %><%= t('garden_houses.meta_description') %><% end %>
<% content_for(:og_image) do %><%= cl_image_path("https://res.cloudinary.com/www-ibizagardenhouses-com/image/upload/c_scale,h_630,w_1200/v1558696079/ibi-3/image.jpg") %><% end %>
<% content_for(:og_description) do %><%= t('garden_houses.meta_description') %><% end %>
<%= render 'first-banner-results' %>
<% if @houses.count >= 4 %>
  <div class="container catalog">
    <%= render "filter_buttons" %>
    <div class="row">
      <% @houses.each do |house| %>
      <div class="col-sm-6 col-md-4">
        <div class="card">
          <% if house.pictures? %>
            <div class="imageTop" style="position: relative;">
              <%= cl_image_tag(house.pictures[0], :quality=>50, :width=>1800, :crop=>"scale", class: "card-img-top", alt: house.name + " " + house.category.name) %>
              <%= link_to "", house_path(house), class: "card-link" %>
            </div>
          <% end %>
          <div class="card-body indexBody">
            <div class="card-price">
              <h3 class="card-title"><%= house.name %></h3>
              <h3><%= house.length.to_f / 100 %> x <%= house.width.to_f.to_f / 100 %> m</h3>
            </div>
            <div class="card-price">
            <% if house.price_present == false %>
                <h3><%= t('show.consult') %></h3>
            <% else %>
                <h3><%= humanized_money_with_symbol(house.original_price) %><span style="color: red"> - 15%</span> = <%= humanized_money_with_symbol(house.price) %></h3>
              <% end %>
            </div>
            <% if policy(house).update? %>
              <%= link_to "Edit", edit_house_path(house) %>
            <% end %>
            <% if policy(house).destroy? %>
              <%= link_to "Remove", house_path(house), method: :delete, data: { confirm: "Are you sure?" } %>
            <% end %>
          </div>
        </div>
      </div>
      <% end %>
    </div>
  </div>
  <%= render "last-banner" %>
<% else %>
  <div class="container catalog">
    <%= render "filter_buttons" %>
    <div class="row">
      <% @houses.each do |house| %>
      <div class="col-sm-6">
        <div class="card">
          <% if house.pictures? %>
            <div class="imageTop" style="position: relative;">
              <%= cl_image_tag(house.pictures[0], :quality=>50, :width=>1800, :crop=>"scale", class: "card-img-top-alt", alt: house.name + " " + house.category.name) %>
              <%= link_to "", house_path(house), class: "card-link" %>
            </div>
          <% end %>
          <div class="card-body indexBody">
            <div class="card-price">
              <h3 class="card-title"><%= house.name %></h3>
              <h3><%= house.length.to_f / 100 %> x <%= house.width.to_f.to_f / 100 %> m</h3>
            </div>
            <div class="card-price">
            <% if house.price_present == false %>
                <h3><%= t('show.consult') %></h3>
            <% else %>
                <h3><%= humanized_money_with_symbol(house.original_price) %><span style="color: red"> - 15%</span> = <%= humanized_money_with_symbol(house.price) %></h3>
              <% end %>
            </div>
            <% if policy(house).update? %>
              <%= link_to "Edit", edit_house_path(house) %>
            <% end %>
            <% if policy(house).destroy? %>
              <%= link_to "Remove", house_path(house), method: :delete, data: { confirm: "Are you sure?" } %>
            <% end %>
          </div>
        </div>
      </div>
      <% end %>
    </div>
  </div>
  <%= render "last-banner" %>
<% end %>

这与 app/views/houses/results_index.html.erb 完全相同的 html,但我在与主页不同的布局中显示所有房屋 (params[h: 1])。这里的问题与过滤结果页面上的问题相同。

<% content_for(:title) do %><%= t('topbar.brand') %><% end %>
<% content_for(:og_site_name) do %><%= t('topbar.brand') %><% end %>
<% content_for(:description) do %><%= t('garden_houses.meta_description') %><% end %>
<% content_for(:og_image) do %><%= cl_image_path("https://res.cloudinary.com/www-ibizagardenhouses-com/image/upload/c_scale,h_630,w_1200/v1558696079/ibi-3/image.jpg") %><% end %>
<% content_for(:og_description) do %><%= t('garden_houses.meta_description') %><% end %>
<%= render 'first-banner-all' %>
<% if @houses.count >= 4 %>
  <div class="container catalog">
    <%= render "filter_buttons" %>
    <div class="row">
      <% @houses.each do |house| %>
      <div class="col-sm-6 col-md-4">
        <div class="card">
          <% if house.pictures? %>
            <div class="imageTop" style="position: relative;">
              <%= cl_image_tag(house.pictures[0], :quality=>50, :width=>1800, :crop=>"scale", class: "card-img-top", alt: house.name + " " + house.category.name) %>
              <%= link_to "", house_path(house), class: "card-link" %>
            </div>
          <% end %>
          <div class="card-body indexBody">
            <div class="card-price">
              <h3 class="card-title"><%= house.name %></h3>
              <h3><%= house.length.to_f / 100 %> x <%= house.width.to_f.to_f / 100 %> m</h3>
            </div>
            <div class="card-price">
            <% if house.price_present == false %>
                <h3><%= t('show.consult') %></h3>
            <% else %>
                <h3><%= humanized_money_with_symbol(house.original_price) %><span style="color: red"> - 15%</span> = <%= humanized_money_with_symbol(house.price) %></h3>
              <% end %>
            </div>
            <% if policy(house).update? %>
              <%= link_to "Edit", edit_house_path(house) %>
            <% end %>
            <% if policy(house).destroy? %>
              <%= link_to "Remove", house_path(house), method: :delete, data: { confirm: "Are you sure?" } %>
            <% end %>
          </div>
        </div>
      </div>
      <% end %>
    </div>
  </div>
  <%= render "last-banner" %>
<% else %>
  <div class="container catalog">
    <%= render "filter_buttons" %>
    <div class="row">
      <% @houses.each do |house| %>
      <div class="col-sm-6">
        <div class="card">
          <% if house.pictures? %>
            <div class="imageTop" style="position: relative;">
              <%= cl_image_tag(house.pictures[0], :quality=>50, :width=>1800, :crop=>"scale", class: "card-img-top-alt", alt: house.name + " " + house.category.name) %>
              <%= link_to "", house_path(house), class: "card-link" %>
            </div>
          <% end %>
          <div class="card-body indexBody">
            <div class="card-price">
              <h3 class="card-title"><%= house.name %></h3>
              <h3><%= house.length.to_f / 100 %> x <%= house.width.to_f.to_f / 100 %> m</h3>
            </div>
            <div class="card-price">
            <% if house.price_present == false %>
                <h3><%= t('show.consult') %></h3>
            <% else %>
                <h3><%= humanized_money_with_symbol(house.original_price) %><span style="color: red"> - 15%</span> = <%= humanized_money_with_symbol(house.price) %></h3>
              <% end %>
            </div>
            <% if policy(house).update? %>
              <%= link_to "Edit", edit_house_path(house) %>
            <% end %>
            <% if policy(house).destroy? %>
              <%= link_to "Remove", house_path(house), method: :delete, data: { confirm: "Are you sure?" } %>
            <% end %>
          </div>
        </div>
      </div>
      <% end %>
    </div>
  </div>
  <%= render "last-banner" %>
<% end %>

如您所见,有很多重复的代码(不是很 DRY),所以我需要一些帮助来获得更多 DRY 并让房屋按类别 ID 排序,然后按价格排序。

感谢您的帮助。

【问题讨论】:

  • 你提到你尝试了一些东西,究竟是什么?

标签: ruby-on-rails ruby


【解决方案1】:

到目前为止,我还不清楚您尝试了什么,但如果您只需要按category_id 排序,我认为您可以在您的房屋模型中定义一个scope,如下所示:

scope :sort_by_category_id_asc, ->{
    order(arel_table[:category_id].asc)
  }

然后您可以使用该范围如下:House.where(...).sort_by_category_id_asc,也可以使用desc,这取决于您要如何订购结果。

希望这会有所帮助! ?

【讨论】:

    【解决方案2】:

    我创建了一个可以通过category_id 对房屋进行排序的方法。如果您想按其他事物对其进行排序,只需将 category_id 更改为您想要的事物。您可以按升序或降序对其进行排序。这里是:

    def sort_by_category_id(houses, order)
      case order_by
        when "asc"
          houses = houses.sort_by{ |house|
            house[:category_id]
          }
          
        when "desc"
          house= house.sort_by{ |house|
            house[:category_id]
          }.reverse!
      end
      house
    end
    

    不要忘记在您希望它工作的任何地方调用此方法。下面的代码将按 category_id 对您的房屋进行排序并将其保存在 sorted_houses 变量中。我

    sorted_houses_asc = sort_by_category_id(@houses, "asc")
    sorted_houses_desc = sort_by_category_id(@houses, "desc")
    

    希望这对您有所帮助。

    【讨论】:

    • 这是一个很好的解决方案,这样做的缺点是您对内存而不是对数据库的查询进行排序(在数据库级别),请记住,如果您有足够的数据,这种方法可以让你慢下来@Minjin Gelegdorj,但绝对是一种有效的方法
    • 乐于助人?
    猜你喜欢
    • 2014-02-17
    • 2016-08-15
    • 2019-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-05
    • 1970-01-01
    相关资源
    最近更新 更多