明年将大幅涨薪的 20 种 IT 职位

明年将大幅涨薪的 20 种 IT 职位

Advertisements

How to deal with n+1 problem when find name by id with rails?

Model

app/models/product.rb

# == Schema Information
#
# Table name: products
#
# id
# name
# 

class Product < ActiveRecord
  has_many :product_items, foreign_key: :product_id, dependent: :destroy
  accepts_nested_attributes_for :product_items
end

app/models/product_item.rb

# == Schema Information
#
# Table name: product_items
#
# id
# product_id
# note_id
# description
# 

class ProductItem < ActiveRecord
  belongs_to :product
  belongs_to :note

  scope :note_info, -> { includes(:note) }
end

app/models/note.rb

# == Schema Information
#
# Table name: notes
#
# id
# name
# 

class Note < ActiveRecord
  has_many :product_items, foreign_key: :note_id
end

Controller

app/controllers/products_controller.rb

class ProductsController < ApplicationController
  def show
  end

  private

  def set_product
    @product = Product.find(params[:id])
  end
end

View

app/views/products/show.html.erb

<% if @product.product_items.present? %>
  <% @product.product_items.note_info.each do |item| %>
    
<% end %> <% end %>

Query

Changed from

D, [2015-09-17T11:16:53.812837 #16844] DEBUG -- :   Product Load (0.1ms)  SELECT  `products`.* FROM `products` WHERE `products`.`id` = 1 LIMIT 1
D, [2015-09-17T11:16:53.818248 #16844] DEBUG -- :   ProductItem Load (0.9ms)  SELECT `product_items`.* FROM `product_items` WHERE `product_items`.`product_id` = 1
D, [2015-09-17T11:16:53.820713 #16844] DEBUG -- :   Note Load (0.1ms)  SELECT  `notes`.* FROM `notes` WHERE `notes`.`id` = 36 LIMIT 1
D, [2015-09-17T11:16:53.823019 #16844] DEBUG -- :   Note Load (0.1ms)  SELECT  `notes`.* FROM `notes` WHERE `notes`.`id` = 35 LIMIT 1
D, [2015-09-17T11:16:53.824233 #16844] DEBUG -- :   Note Load (0.1ms)  SELECT  `notes`.* FROM `notes` WHERE `notes`.`id` = 39 LIMIT 1
D, [2015-09-17T11:16:53.826517 #16844] DEBUG -- :   Note Load (0.1ms)  SELECT  `notes`.* FROM `notes` WHERE `notes`.`id` = 42 LIMIT 1
D, [2015-09-17T11:16:53.830015 #16844] DEBUG -- :   Note Load (0.1ms)  SELECT  `notes`.* FROM `notes` WHERE `notes`.`id` = 28 LIMIT 1
D, [2015-09-17T11:16:53.834301 #16844] DEBUG -- :   Note Load (0.3ms)  SELECT  `notes`.* FROM `notes` WHERE `notes`.`id` = 11 LIMIT 1
D, [2015-09-17T11:16:53.837405 #16844] DEBUG -- :   Note Load (0.2ms)  SELECT  `notes`.* FROM `notes` WHERE `notes`.`id` = 12 LIMIT 1
D, [2015-09-17T11:16:53.840325 #16844] DEBUG -- :   Note Load (0.1ms)  SELECT  `notes`.* FROM `notes` WHERE `notes`.`id` = 50 LIMIT 1

to

D, [2015-09-17T11:29:50.280367 #18842] DEBUG -- :   Product Load (0.3ms)  SELECT  `products`.* FROM `products` WHERE `products`.`id` = 1 LIMIT 1
D, [2015-09-17T11:29:50.315951 #18842] DEBUG -- :   ProductItem Load (0.3ms)  SELECT `product_items`.* FROM `product_items` WHERE `product_items`.`product_id` = 1
D, [2015-09-17T11:29:50.323917 #18842] DEBUG -- :   CACHE (0.0ms)  SELECT `product_items`.* FROM `product_items` WHERE `product_items`.`product_id` = 1  [["product_id", 1]]
D, [2015-09-17T11:29:50.349202 #18842] DEBUG -- :   Note Load (0.3ms)  SELECT `notes`.* FROM `notes` WHERE `notes`.`id` IN (36, 35, 39, 42, 28, 11, 12, 50)

Reference

How to show the right i18n messages for two relationship models with Rails?

Models

app/models/product.rb

class Product < ActiveRecord::Base
  has_many :product_items, foreign_key: :product_id, dependent: :destroy
  accepts_nested_attributes_for :product_items

  validates :name, presence: true
end

app/models/product_item.rb

class ProductItem < ActiveRecord::Base
  belongs_to :product

  validates :description, presence: true
end

i18n files

config/locales/products.ja.yml

ja:

  activerecord:
    attributes:

      product:
        name: '名前'

config/locales/product_items.ja.yml

ja:

  activerecord:
    attributes:

      product/product_items:
        description: '説明'

View

app/views/products/_form.html.erb

<%= form_for(product, url: path) do |f| %>
  <% if f.object.errors.any? %>
    
</div> <% end %> <%= f.label :name %> <%= f.text_field :name %> <%= f.fields_for :product_items do |item_form| %> <%= item_form.label :description %> <%= item_form.text_field :description %> <% end %> <%= f.submit 'Submit' %> <% end %>

Reference

How to save two relationship record in one form at the same time with Rails?

Model

app/models/product.rb

class Product < ActiveRecord::Base
  has_many :product_items, foreign_key: :product_id, :dependent => :destroy
  accepts_nested_attributes_for :product_items
end

app/models/product_item.rb

class ProductItem < ActiveRecord::Base
  belongs_to :product
end

Controller

app/controllers/products_controller.rb

class ProductController < ApplicationController
  def new
    @product = Product.new
    @product.product_items.build
  end

  def create
    @product = Product.new(product_params)
    respond_to do |format|
      if @product.save
        format.html { redirect_to root_path }
      else
        format.html { render :new }
      end
    end
  end

  def edit
  end

  def update
    respond_to do |format|
      if @product.update(product_params)
        format.html { redirect_to root_path }
      else
        render :edit
      end
    end
  end

  private

  def set_product
    @product = Product.find(params[:id])
  end

  def product_params
    params.require(:product).permit(:name, product_items_attributes: [ :id, :description ])
  end
end

View

app/views/products/_form.html.erb

<%= form_for(product, url: path) do |f| %>
  <%= f.label :name %>
  <%= f.text_field :name %>

  <%= f.fields_for :product_items do |item_form| %>
    <%= item_form.label :description %>
    <%= item_form.text_field :description %>
  <% end %>

  <%= f.submit 'Submit' %>
<% end %>

Reference