如何计算 nested_attribute 布尔值?

How to .count nested_attribute boolean?

量化的嵌套属性是结果。在结果部分中,用户将核对他们的量化结果是否为 :good

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

边栏部分: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
                               
                            

非常感谢您的宝贵时间!

您可以按如下方式更新您的 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

当创建新的 Results 时 through Quantifieds,这就是你在 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 设置正确。

如何解决?

通过简化关联! Result中不需要同时存储quantify_iduser_id

如果有这样的关系:User 有很多 Quantifies,而 Quantify 有很多 Results,你可以很容易地访问 Results通过在 User 中适当声明的 Users:

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 ...>

现在,按上述方式设置关系后,正确的计数应该会出现在网站中。

Result中不需要存储user_id,可以随意删除!

<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>