如何从数据库中提取评论并在gridview中显示

时间:2018-05-22 15:34:55

标签: ruby-on-rails

我按照教程在Ruby on Rails上建立了一个餐厅评论网站,并将其改编为医院。

我想在网格视图中以最高评论或最高评论数量或按位置(数据库中所有可用数据)的排序格式显示数据库中的结果(仅限前六名)。

我不确定从哪里开始,我知道这可能听起来很简单,但我已经研究过,并且看到了很多选项,并对从何处开始感到困惑。 一些解决方案似乎适合小型数据集,但我完全希望它在未来呈指数级增长,因此最有效的方式对我来说是最好的。 我的本地环境中有SQLlite,生产环境中有Postgres。

这就是我在搜索页面上显示的所有医院以及我在索引页面中显示的内容,该页面显示网格中的所有记录。非常感谢任何帮助。

search.html.erb

<div class="table-responsive table-box card"> 
  <%= form_tag search_hospitals_path, method: :get, class: "form-group" do %>
  <div class="input-group">
    <div class="input-group-addon">Search and Review</div>
          <p>
            <%= text_field_tag :search, params[:search],  class: "form-control formInput", placeholder: "Hospital Name" %>
          </p>
  </div>
    <% end %>

    <div class="container hospital_display">
      <% @hospitals.each do |hospital| %>
        <div class="row">
            <div class="col-sm-6">                
              <%= link_to image_tag(hospital.image), hospital, class: "responsive" %>
            </div>
              <div class="col-sm-6">
                  <%= link_to hospital.name, hospital %><br>
                  <%= hospital.address %><br>
                  <%= hospital.phone %><br>
                  <%= link_to hospital.website, hospital.website %>
                  <%# Checks for admin %>
                  <% if user_signed_in? && current_user.admin? %>
                    <%= link_to 'Edit', edit_hospital_path(hospital), class: "btn btn-link" %>
                    <%= link_to 'Destroy', hospital, method: :delete, data: { confirm: 'Are you sure?' }, class: "btn btn-link" %>
                  <% end%>
                  <%# Rating %>
                  <% if hospital.reviews.count == 0 %>
                    No reviews yet, be the first to write one
                  <% elsif hospital.reviews.count == 1 %>
                  <div class="star-rating" data-score= <%= hospital.avg_rating %> ></div>
                    1 Review
                  <% else %>
                  <div class="star-rating" data-score= <%= hospital.avg_rating %> ></div>
                    <%= hospital.length %> <%= "Reviews" %>
                <% end %>
              </div>
            </div>
          <% end %>
      </div>
    </div>
  </div>
</div>
<br>

<script>
    $('.star-rating').raty({
        path: 'https://s3-us-west-2.amazonaws.com/morafamedapp/stars',
        readOnly: true,
        score: function() {
            return $(this).attr('data-score');
        }
    });
</script>

我在索引页面上有这个 的 index.html.erb

<div class="jumboFluid">
<div class="jumbotron">
<section class="content">


<%= form_tag search_hospitals_path, method: :get, class: "form-group" do %>
<div class="input-group">
<div class="input-group-addon">Search</div>
        <p>
          <%= text_field_tag :search, params[:search],  class: "form-control formInput", placeholder: "Eye, Maternity" %>
          <%# <%= submit_tag "Search", name: nil, class: "btn btn-default" %>
        </p>
</div>
  <% end %><br>



  <h3 class="intro2">Find the best HealthCare Options around you with Medapp.
  <br><%# Explore the best of healthcare available in your community.<br>
    Read and leave reviews to assist others seeking the best health care and keep our hospitals on their toes. %></h3>
</section>
</div>
</div>
<div class="hospitalList">
<h1 id="hospitalBanner">Hospitals</h1>
<blockquote> 
  <p class="text-center"><cite>&#8220;Explore the best of healthcare available in your community&#8221;</cite> </p>
</blockquote>

<% content_for(:body_attributes) do %>
    data-no-turbolink="false"
  <% end %>
<main>
<div class="container-fluid fluid">
<div class="row">
<% @hospitals.each do |hospital| %>
  <div class="col-md-4 col-xs-6">
    <div class="thumbnail">
        <%= link_to image_tag(hospital.image), hospital %>
        <div class="caption">
          <h4> <%= link_to hospital.name, hospital %></h4><br>
          <% if hospital.reviews.count == 0 %>
            0 Reviews
          <% elsif hospital.reviews.count == 1 %>
            <div class="star-rating" data-score= <%= hospital.avg_rating %> ></div>
            1 Review
            <% else %>
            <div class="star-rating" data-score= <%= hospital.avg_rating %> ></div>
            <%= hospital.length %> <%= "Reviews" %>
          <% end %>
    </div>
  </div>
  </div>
<% end %>
 </div>

</main>


<br>

<% if user_signed_in? && current_user.admin? %>
  <%= link_to 'New Hospital', new_hospital_path, class: "btn btn-primary btn-lg btn-special" %>
<% end %>

<!--Start of Tawk.to Script-->
<script type="text/javascript">
window.$_Tawk = undefined;
var Tawk_API=Tawk_API||{}, Tawk_LoadStart=new Date();
(function(){
var s1=document.createElement("script"),s0=document.getElementsByTagName("script")[0];
s1.async=true;
s1.src='https://embed.tawk.to/592da976b3d02e11ecc677a1/default';
s1.charset='UTF-8';
s1.setAttribute('crossorigin','*');
s0.parentNode.insertBefore(s1,s0);
s1.style.background = 'yellow';
})();
</script>
<!--End of Tawk.to Script-->

<script>
  $('.star-rating').raty({
    path: 'https://s3-us-west-2.amazonaws.com/morafamedapp/stars',
    readOnly: true,
    score: function() {
      return $(this).attr('data-score');
    }
  });
</script>

</div>

Hospitals_controller.rb

class HospitalsController < ApplicationController
  before_action :set_hospital, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!, except: [:search, :index, :show]
  before_action :check_user, except: [:search, :index, :show]
  protect_from_forgery with: :null_session
  protect_from_forgery except: ["create"]

  def search
    if params[:search].present?
      @hospitals = Hospital.search(params[:search])
    else
      @hospitals = Hospital.all
    end
  end

  def import
   Hospital.import(params[:file])
  end


  # GET /hospitals
  # GET /hospitals.json
  def index
    @hospitals = Hospital.all
  end

  # GET /hospitals/1
  # GET /hospitals/1.json
  def show
    @reviews = Review.where(hospital_id: @hospital.id).order("created_at DESC")
    if @reviews.blank?
      @avg_rating = 0
    else
    @avg_rating = @reviews.average(:rating).round(2)
    end
  end

  # GET /hospitals/new
  def new
    @hospital = Hospital.new
  end

  # GET /hospitals/1/edit
  def edit
  end

  # POST /hospitals
  # POST /hospitals.json
  def create
    import if params[:file] # <= this here is the call to your import method

    @hospital = Hospital.new(hospital_params)

    respond_to do |format|
      if @hospital.save
        format.html { redirect_to @hospital, notice: 'Hospital was successfully created.' }
        format.json { render :show, status: :created, location: @hospital }
      else
        format.html { render :new }
        format.json { render json: @hospital.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /hospitals/1
  # PATCH/PUT /hospitals/1.json
  def update
    respond_to do |format|
      if @hospital.update(hospital_params)
        format.html { redirect_to @hospital, notice: 'Hospital was successfully updated.' }
        format.json { render :show, status: :ok, location: @hospital }
      else
        format.html { render :edit }
        format.json { render json: @hospital.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /hospitals/1
  # DELETE /hospitals/1.json
  def destroy
    @hospital.destroy
    respond_to do |format|
      format.html { redirect_to hospitals_url, notice: 'Hospital was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_hospital
      @hospital = Hospital.find(params[:id])
    end

    def check_user
    unless current_user.admin?
        redirect_to root_url, alert: "Sorry, only admins can do that!"
    end
  end

    # Never trust parameters from the scary internet, only allow the white list through.
    def hospital_params
      params.require(:hospital).permit(:name, :address, :city_town, :state,  :phone, :website, :safe_care, :jci, :cohsasa, :best_known_4, :image )
    end
end

1 个答案:

答案 0 :(得分:0)

如果您不关心访问该值本身,只想要我建议使用andrew21s answer的订单。有了这个,让我们回答。

这个问题很简单,虽然答案比你想象的要复杂得多。我假设模型中有以下关联:

class Hospital < ApplicationRecord
  has_many :reviews
end

class Review < ApplicationRecord
  belongs_to :hospital
end

通过以上目前,可以通过以下范围解决此问题:

class Hospital < ApplicationRecord

  # ...

  def self.include_review_count
    review_count = Review.select(Review.arel_table[:id].count)
                         .where(Review.arel_table[:hospital_id].eq(arel_table[:id]))
                         .as('review_count')

    select(*attribute_names.map(&:to_sym)).select(review_count)
  end

  def self.include_review_average
    review_average = Review.select(Review.arel_table[:rating].average)
                           .where(Review.arel_table[:hospital_id].eq(arel_table[:id]))
                           .as('review_average')

    select(*attribute_names.map(&:to_sym)).select(review_average)
  end

  # ...

end

有了这些范围,您现在可以在控制器中执行以下操作:

class HospitalsController < ApplicationController

  # ...

  def index
    @hospitals = Hospital.include_review_count
                         .include_review_average
                         .order('review_count DESC', 'review_average DESC', :id)
                         .limit(6)
  end

  # ...

end
  

注意:在上面的代码中,您无法使用.order(review_count: :desc, review_average: :desc, id: :asc),因为“review_count”不是真正的属性,而只是一个别名。因此,您必须使用文字(String)变体。在 where 语句中使用此添加的属性时也是如此。例如:.where(review_count: 2)不起作用,而.where('review_count = ?', 2)确实起作用。

此解决方案只进行一次查询,并允许您访问值而无需其他查询。一个例子可能是(index.html.erb):

<table>
  <thead>
    <tr>
      <th>ID</th>
      <th>Name</th>
      <th>Review Count</th>
      <th>Review Average</th>
    </tr>
  </thead>
  <tbody>
    <% @hospitals.each do |hospital| %>
      <tr>
        <td><%= hospital.id %></td>
        <td><%= hospital.name %></td>
        <td><%= hospital.review_count %></td>
        <td><%= hospital.review_average %></td>
      </tr>
    <% end %>
  </tbody>
</table>