Save item content information ~ Active_Hash ~

When implementing the information registration format, it is inevitable to save the selected items (collection, etc.) in the DB. For apps such as flea market, you need to register the prefecture, product status, delivery time, etc. If you assume a questionnaire, you can see it in various situations such as gender and date of birth. I think that many people assume that the item contents are prepared in advance in seed.rb etc. to create a table, but it is no exaggeration to say that this is a useless table.

Useless table? "Normalization" is often used in DB design. Roughly speaking, it's about making the structure of your data efficient and simple. However, if this normalization is performed thoroughly, the number of small tables will increase, which also contributes to the processing load. Therefore, it is necessary to avoid creating a table dedicated to items as much as possible.

Active_hash is useful in such a case.

What is Active_hash? By creating a dedicated model and preparing the value of the item content in it in advance, it is possible to prepare the item without going through the DB. So to speak, you will create an "item table in the model". By doing this, it is not necessary to prepare a small table on the DB side, so the load is lightened.

Installation procedure This time, I will implement it assuming a product questionnaire using collection_select. The following four contents are to be saved and managed. ・ Age ·sex ・ History of learning about the product ・ Impressions of using the product

I want to have one table considering the DB load. As a design

  1. Ages are teens to 90s
  2. Gender is male / female
  3. How did you get to know the product? Advertising, acquaintances, family, internet
  4. Manually enter your impressions of using the product I will continue.

Of these, the items (collection_select) that you want to use are the contents 1 to 3. Let's assume this and implement the questionnaire. Please note that this explanation is limited to the implementation of active_hash, and the other steps are omitted.

Step: 1 Add active_hash to Gemfile and execute installation

gem 'active_hash'

Terminal

% bundle install

Step: 2 Preparation of model & migration file

Generate a model with the g command * Model name is your choice

% rails g model model question

・ Preparation of migration file

When using active_hash Item contents are managed by integer column. This integer column works as an id. Therefore, be sure to add "_id" to the column name. The manual input field is implemented with the usual text column.

00000000000000_create_questions.rb

class CreateQuestions < ActiveRecord::Migration[6.0]
  def change
    create_table :questions do |t|
      t.integer :age_id,         null: false
      t.integer :sexuality_id,   null: false
      t.integer :find_item_id,   null: false
      t.text    :comment,        null: false
      t.timestamps
    end
  end
end

Then create the table as usual and run the migration file.

% rails db:create
% rails db:migrate

-Create a model file for each item Prepare a model that implements active_hash for 3 items. The migration file is not needed, so add an option to skip it.

% rails g model age --skip-migration
% rails g model sexuality --skip-migration
% rails g model find_item --skip-migration

Let's write the contents of the model prepared for each item

The inside of the generated model probably looks like this at the beginning

class Age < ApplicationRecord
end

To make this a model dedicated to active_hash, edit it as follows.

class Age < ActiveHash::Base
end

This makes it possible to create a pseudo item table within this model. When putting items in this, we will implement it using class methods and hashes. The point to improve readability is to use the first key as id and "give the other key the name you want to treat as an item. Example

class class name< ActiveHash::Base
  self.data = [
  { id: 0, hoge: fuga }]
end

Along with this, it becomes as follows.

class Age < ActiveHash::Base
  self.data = [
      { id: 0, name: '---' },
      { id: 1, name: '10's' },
      { id: 2, name: '20's' },
      { id: 3, name: '30s' },
      { id: 4, name: 'Forties' },
      { id: 5, name: '50s' },
      { id: 6, name: '60s' },
      { id: 7, name: '70s' },
      { id: 8, name: '80s' },
      { id: 9, name: '90s' }
  ]
class FindItem < ActiveHash::Base
  self.data = [
    { id: 0, example: '---' },
    { id: 1, example: 'I learned from the advertisement' },
    { id: 2, example: 'I learned from an acquaintance's introduction' },
    { id: 3, example: 'I learned from my family introduction' },
    { id: 4, example: 'I knew on the internet' }
  ]
end
class Sexuality < ActiveHash::Base
  self.data = [
    { id: 0, name: '---' },
    { id: 1, name: 'male' },
    { id: 2, name: 'Female' }
  ]
end

This completes the creation of the pseudo table using active_hash. After that, I will give a description to link with the question model that was created first, which is the basis.

class Question < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to_active_hash :age
  belongs_to_active_hash :sexuality
  belongs_to_active_hash :find_item
end

Step: 3 View file description
<h1>Please cooperate with the questionnaire about our products</h1>

<div class="wrapper">
  <div class="form">
    <%= form_with model: @question, local: true do |f| %>
      <div class="form-box">
        <h3>Please select the age</h3>
        <%= f.collection_select(:age_id, Age.all, :id, :name) %>
      </div>
      <div class="form-box">
        <h3>Please select your gender</h3>
        <%= f.collection_select(:sexuality_id, Sexuality.all, :id, :name)%>
      </div>
      <div class="form-box">
        <h3>Where did you find out about our products?</h3>
        <%= f.collection_select(:find_item_id, FindItem.all, :id, :example)%>
      </div>
      <div class="form-text">
        <h3>Please write down your impressions of using our products as it is easy to use.</h3>
        <%= f.text_area :comment %>
      </div>
      <%= f.submit "Send" %>
    <% end %>
  </div>
</div>

The point is the argument of collection_select. The first argument is the value passed to params (column name), and the second argument is the item (model name) you want to display.

Step: 4 Controller description
class QuestionsController < ApplicationController
  def index
    @question = Question.new
  end

  def create
    # binding.pry
    @question = Question.new(question_params)
    @question.save
    redirect_to root_path
  end

  private
  def question_params
    params.require(:question).permit(
      :age_id, 
      :sexuality_id, 
      :find_item_id, 
      :comment)
  end
end

There is no particular mention here.

I tried to implement it briefly

Please try active_hash by all means.

Recommended Posts

Save item content information ~ Active_Hash ~