如何.count嵌套属性布尔值?

时间:2015-03-13 21:02:40

标签: ruby-on-rails ruby boolean nested-attributes sidebar

量化的嵌套属性是结果。在结果中,用户将检查其量化结果是否为:good

在侧边栏中,我想.count用户标记了多少好成绩,作为他们成功的参考点。

SIDEBAR SECTION:layouts / _count.html.erb

<div class="stats">
  <a href="<%= following_user_path(@user) %>">
    <strong id="following" class="stat">
      <%= @user.quantifieds.count %> #Works
    </strong>
    Quantified
  </a>
  &nbsp;
  <a href="<%= followers_user_path(@user) %>">
    <strong id="followers" class="stat">
      <%= @user.results.good.count %> #Remains zero regardless of number of checked :good boxes
    </strong>
    Good
  </a>
</div>

quantifieds / _result_fields.html.erb

<div class="nested-fields">
  <div class="form-group">
    <%= f.text_field :result_value, class: 'form-control', placeholder: 'Enter Result' %>
    <br/>
		<%= f.date_select :date_value, :order => [:month, :day, :year], :with_css_classes => true, :class => "modular-date-field" %>
    <b><%= link_to_remove_association "Remove Result", f %></b>
  <div class="america3">
  <label> Good: </label>
  <%= f.check_box :good %>
  </div>
  </div>
</div>

result.rb

class Result < ActiveRecord::Base
	belongs_to :user
  belongs_to :quantified
  default_scope { order('date_value DESC') }
	scope :good, -> { where(good: true) }
	scope :bad, -> { where(good: false) }
end

我们是否应该向应用程序控制器添加方法

class ApplicationController < ActionController::Base
  before_action :load_todays_habits
  before_action :set_top_3_goals
  before_action :randomize_value
  before_action :set_stats
  protect_from_forgery with: :exception
  include SessionsHelper

  def set_top_3_goals
    @top_3_goals = current_user.goals.unaccomplished.top_3 if current_user
  end

  def randomize_value
    @sidebarvaluations = current_user.valuations.randomize if current_user
  end

  def set_stats
    @quantifieds = Quantified.joins(:results).all
    @averaged_quantifieds = current_user.quantifieds.averaged if current_user
    @instance_quantifieds = current_user.quantifieds.instance if current_user
  end

  private 

  def load_todays_habits
    @user_tags = current_user.habits.committed_for_today.tag_counts if current_user
    @all_tags  = Habit.committed_for_today.tag_counts if current_user
  end

  # Confirms a logged-in user.
  def logged_in_user
    unless logged_in?
      store_location
      flash[:danger] = "Please log in."
      redirect_to login_url
    end
  end
end

class QuantifiedsController < ApplicationController
  before_action :set_quantified, only: [:show, :edit, :update, :destroy]
  before_action :logged_in_user, only: [:create, :destroy]

  def index
    if params[:tag]
      @quantifieds = Quantified.tagged_with(params[:tag])
    else
      @quantifieds = Quantified.joins(:results).all
      @averaged_quantifieds = current_user.quantifieds.averaged
      @instance_quantifieds = current_user.quantifieds.instance
    end
  end

  def show
  end

  def new
    @quantified = current_user.quantifieds.build 
  end

  def edit
  end

  def create
    @quantified = current_user.quantifieds.build(quantified_params)
    if @quantified.save
      redirect_to quantifieds_url, notice: 'Quantified was successfully created'
    else
      @feed_items = []
      render 'pages/home'
  end
end

  def update
    if @quantified.update(quantified_params)
      redirect_to quantifieds_url, notice: 'Goal was successfully updated'
    else
      render action: 'edit'
  end
end

  def destroy
    @quantified.destroy
    redirect_to quantifieds_url
  end

  private
    def set_quantified
      @quantified = Quantified.find(params[:id])
    end

    def correct_user
      @quantified = current_user.quantifieds.find_by(id: params[:id])
      redirect_to quantifieds_path, notice: "Not authorized to edit this goal" if @quantified.nil?
    end

    def quantified_params
      params.require(:quantified).permit(:categories, :metric, :result, :date, :comment, :private_submit, :tag_list, :good, results_attributes: [:id, :result_value, :date_value, :good, :_destroy])
    end
end

quantifieds / _form

<%= javascript_include_tag "quantified.js" %>

<%= simple_form_for(@quantified) do |f| %>
  <%= f.error_notification %>

<div class="america">
<form>
  
  <% Quantified::CATEGORIES.each do |c| %>&nbsp;
    <%= f.radio_button(:categories, c, :class => "date-format-switcher") %>&nbsp;
    <%= label(c, c) %>
  <% end %>
      <br/>
      <br/>
      <div class="form-group">
        <%= f.text_field :tag_list, quantified: @quantified.tag_list.to_s.titleize, class: 'form-control', placeholder: 'Enter Action' %>
      </div>
      <div class="form-group">
        <%= f.text_field :metric,  class: 'form-control', placeholder: 'Enter Metric' %>
      </div>

    <div id="results">
      <%= f.fields_for :results do |result| %>
      <%= render 'result_fields', :f => result %>
      <% end %>
    </div>
    
    <div class="links">
      &nbsp;&nbsp;<b><%= link_to_add_association 'Add Result', f, :results %></b>
    </div>

<div class="america2">
  <%= button_tag(type: 'submit', class: "btn") do %>
  <span class="glyphicon glyphicon-plus"></span>
  <% end %>

  <%= link_to quantifieds_path, class: 'btn' do %>
  <span class="glyphicon glyphicon-chevron-left"></span>
  <% end %>

  <%= link_to @quantified, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn' do %>
  <span class="glyphicon glyphicon-trash"></span>
  <% end %>
</div>

  <label> Private: </label>
  <%= f.check_box :private_submit %>
  
</form>
</div>
<% end %>

quantifieds.rb

class Quantified < ActiveRecord::Base
	belongs_to :user
 	has_many :results #correct
	has_many :comments, as: :commentable
	accepts_nested_attributes_for :results, :reject_if => :all_blank, :allow_destroy => true #correct
 	scope :averaged,  -> { where(categories: 'Averaged') }
 	scope :instance,  -> { where(categories: 'Instance') }
	scope :private_submit, -> { where(private_submit: true) }
	scope :public_submit, -> { where(private_submit: false) }
 	validates :categories, :metric, presence: true
	acts_as_taggable

	CATEGORIES = ['Averaged', 'Instance']
end

schema.rb

# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20150317171422) do

  create_table "activities", force: true do |t|
    t.integer  "trackable_id"
    t.string   "trackable_type"
    t.integer  "owner_id"
    t.string   "owner_type"
    t.string   "key"
    t.text     "parameters"
    t.integer  "recipient_id"
    t.string   "recipient_type"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "activities", ["owner_id", "owner_type"], name: "index_activities_on_owner_id_and_owner_type"
  add_index "activities", ["recipient_id", "recipient_type"], name: "index_activities_on_recipient_id_and_recipient_type"
  add_index "activities", ["trackable_id", "trackable_type"], name: "index_activities_on_trackable_id_and_trackable_type"

  create_table "comments", force: true do |t|
    t.text     "content"
    t.integer  "commentable_id"
    t.string   "commentable_type"
    t.datetime "created_at",       null: false
    t.datetime "updated_at",       null: false
  end

  add_index "comments", ["commentable_id", "commentable_type"], name: "index_comments_on_commentable_id_and_commentable_type"

  create_table "days", force: true do |t|
    t.integer  "level_id"
    t.integer  "habit_id"
    t.boolean  "missed",     default: false
    t.datetime "created_at",                 null: false
    t.datetime "updated_at",                 null: false
  end

  create_table "goals", force: true do |t|
    t.string   "name"
    t.date     "deadline"
    t.boolean  "accomplished"
    t.boolean  "private_submit"
    t.integer  "user_id"
    t.datetime "created_at",     null: false
    t.datetime "updated_at",     null: false
  end

  add_index "goals", ["user_id", "created_at"], name: "index_goals_on_user_id_and_created_at"
  add_index "goals", ["user_id"], name: "index_goals_on_user_id"

  create_table "habits", force: true do |t|
    t.datetime "left"
    t.integer  "level"
    t.text     "committed"
    t.datetime "date_started"
    t.string   "trigger"
    t.string   "target"
    t.string   "reward"
    t.boolean  "private_submit"
    t.integer  "user_id"
    t.datetime "created_at",     null: false
    t.datetime "updated_at",     null: false
  end

  add_index "habits", ["user_id", "created_at"], name: "index_habits_on_user_id_and_created_at"
  add_index "habits", ["user_id"], name: "index_habits_on_user_id"

  create_table "levels", force: true do |t|
    t.integer  "user_id"
    t.integer  "habit_id"
    t.boolean  "passed",     default: false
    t.datetime "created_at",                 null: false
    t.datetime "updated_at",                 null: false
  end

  create_table "quantifieds", force: true do |t|
    t.string   "categories"
    t.string   "metric"
    t.boolean  "private_submit"
    t.integer  "user_id"
    t.datetime "created_at",     null: false
    t.datetime "updated_at",     null: false
  end

  add_index "quantifieds", ["user_id", "created_at"], name: "index_quantifieds_on_user_id_and_created_at"
  add_index "quantifieds", ["user_id"], name: "index_quantifieds_on_user_id"

  create_table "relationships", force: true do |t|
    t.integer  "follower_id"
    t.integer  "followed_id"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
  end

  add_index "relationships", ["followed_id"], name: "index_relationships_on_followed_id"
  add_index "relationships", ["follower_id", "followed_id"], name: "index_relationships_on_follower_id_and_followed_id", unique: true
  add_index "relationships", ["follower_id"], name: "index_relationships_on_follower_id"

  create_table "results", force: true do |t|
    t.integer  "user_id"
    t.string   "result_value"
    t.date     "date_value"
    t.integer  "quantified_id"
    t.boolean  "good"
    t.datetime "created_at",    null: false
    t.datetime "updated_at",    null: false
  end

  create_table "taggings", force: true do |t|
    t.integer  "tag_id"
    t.integer  "taggable_id"
    t.string   "taggable_type"
    t.integer  "tagger_id"
    t.string   "tagger_type"
    t.string   "context",       limit: 128
    t.datetime "created_at"
  end

  add_index "taggings", ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true
  add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context"

  create_table "tags", force: true do |t|
    t.string  "name"
    t.integer "taggings_count", default: 0
  end

  add_index "tags", ["name"], name: "index_tags_on_name", unique: true

  create_table "users", force: true do |t|
    t.string   "name"
    t.string   "email"
    t.text     "missed_days"
    t.text     "missed_levels"
    t.string   "provider"
    t.string   "uid"
    t.string   "oauth_token"
    t.datetime "oauth_expires_at"
    t.datetime "created_at",                        null: false
    t.datetime "updated_at",                        null: false
    t.string   "password_digest"
    t.string   "remember_digest"
    t.boolean  "admin",             default: false
    t.string   "activation_digest"
    t.boolean  "activated",         default: false
    t.datetime "activated_at"
    t.string   "reset_digest"
    t.datetime "reset_sent_at"
  end

  add_index "users", ["email"], name: "index_users_on_email", unique: true

  create_table "valuations", force: true do |t|
    t.string   "name"
    t.boolean  "private_submit"
    t.integer  "user_id"
    t.datetime "created_at",     null: false
    t.datetime "updated_at",     null: false
  end

  add_index "valuations", ["user_id", "created_at"], name: "index_valuations_on_user_id_and_created_at"
  add_index "valuations", ["user_id"], name: "index_valuations_on_user_id"

end

class User < ActiveRecord::Base
  has_many :authentications
  has_many :habits, dependent: :destroy
  has_many :levels
  has_many :valuations, dependent: :destroy
  has_many :comments, as: :commentable
  has_many :goals, dependent: :destroy
  has_many :quantifieds, dependent: :destroy
  has_many :results, dependent: :destroy
                               
                            

非常感谢你的时间!

2 个答案:

答案 0 :(得分:1)

您可以按如下方式更新Result

class Result < ActiveRecord::Base
  # rest of the code
  scope :good,       -> { where(good: true) }
  scope :good_count, -> { good.count }
end

让我们在rails console中执行一些测试:

u = User.create({ user_attributes })

u.results.create(good: true)
u.results.create(good: false)
u.results.create(good: true)

u.results.count
# => SELECT COUNT(*) FROM "results" WHERE "results"."user_id" = ?  [["user_id", 1]]
# => 3

u.results.good_count
# => SELECT COUNT(*) FROM "results" WHERE "results"."user_id" = ? AND "results"."good" = 't'  [["user_id", 1]]
# => 2

如果您更改了User,如下所示:

class User < ActiveRecord::Base
  # rest of the code
  def good_results_count
    results.good_count
  end
end

这是一个更清洁的解决方案,您可以在您的应用程序中使用它,如:

# assuming we have data set like in previous step
u = User.last

u.good_results_count # you can use this line in your template
# => SELECT COUNT(*) FROM "results" WHERE "results"."user_id" = ? AND "results"."good" = 't'  [["user_id", 1]]
# => 2

如果由于某种原因,该值仍然为0 - 如您所述 - 尝试执行我在控制台中描述的操作以查看数据库中的实际数据。也许这不是提取正确数据的问题,也许数据保存不正确?

让我知道它是怎么回事,所以我们试着解决真正的问题!

祝你好运!

<强>更新

视野中的问题是由于UserResult之间缺乏正确的关联。 User目前的内容:

class User < ActiveRecord::Base
  # rest of the code
  has_many :quantifieds, dependent: :destroy
  has_many :results, dependent: :destroy
  # rest of the code
end

创建新的Result through Quantified后,这就是QuantifiedsController#create中的内容:

class QuantifiedsController < ApplicationController
  def create
    @quantified = current_user.quantifieds.build(quantified_params)
    if @quantified.save
      redirect_to quantifieds_url, notice: 'Quantified was successfully created'
    else
      @feed_items = []
      render 'pages/home'
    end
  end
end

嗯,一切看起来都很完美,但问题实际上在@quantified = current_user.quantifieds.build(quantified_params)。创建的所有Result都有user_id = nil,只有quantified_id设置正确。

如何解决此问题?

通过简化协会!无需在quantify_id中同时存储user_idResult

如果存在如下关系:User有多个Quantifies,而Quantify有很多Results,则可以非常轻松地访问Result个{ {1}} User中的适当声明:{1}}

User

这是非常聪明的事情!让我们看看,幕后发生了什么:

class User < ActiveRecord::Base
  # rest of the code
  has_many :quantifieds, dependent: :destroy
  has_many :results, through: :quantifieds
  # rest of the code
end

现在,当如上所述设置关系时,正确的计数应出现在网站中。

无需在u = User.last u.results Result Load (0.3ms) SELECT "results".* FROM "results" INNER JOIN "quantifieds" ON "results"."quantified_id" = "quantifieds"."id" WHERE "quantifieds"."user_id" = ? ORDER BY date_value DESC [["user_id", 5]] => #<ActiveRecord::Associations::CollectionProxy ...> 中存储user_id,因此您可以自由删除它!

答案 1 :(得分:-1)

<div class="stats">
  <a href="<%= following_user_path(@jadenmcgruder) %>">
    <strong id="following" class="stat">
      <%= @jadenmcgruder.quantifieds.count %> #Works
    </strong>
    Quantified
  </a>
  &nbsp;
  <a href="<%= followers_user _path(@jadenmcgruder) %>">
    <strong id="followers" class="stat">
      <%= @jadenmcgruder.results.good.count %> #Remains zero regardless of number of checked :good boxes
    </strong>
    Good
  </a>
</div>