Rails×Vue.js axios와 ransack으로 검색 양식 만들기

개요


  • Rails5.1 + webpacker + vue.js를 사용하여 응용 프로그램을 만듭니다.
  • 이 기사는 환경 구축을 다루지 않으며 ajax를 사용한 검색 양식에 중점을 둡니다.
  • 작성한 코드는 여기

  • 샘플 앱


  • 간단한 직원 관리 응용 프로그램을 만듭니다.
  • 사용하는 모델은 직원(staff)만.
  • 직원 모델에는 이름(name), 연령(age), 입사일(joined_on) 정보가 있습니다.
  • $ rails g scaffold staff name:string age:integer joined_on:date
    $ rake db:migrate
    

    라우팅


  • ajax에 대한 엔드포인트api/staffs/search를 작성합니다.

  • routes.rb
      root 'staffs#index'
      scope :api, { format: 'json' } do
        resources :staffs do
          get :search , on: :collection
        end
      end
      resources :staffs
    

    Ajax에서 요청 매개변수 보내기



    axios와 qs를 설치합니다.
    $ yarn add axios
    $ yarn add qs
    

    application.js
    import Vue from 'vue/dist/vue.esm'
    import axios from 'axios'
    import Qs from 'qs'
    
    document.addEventListener('DOMContentLoaded', () => {
      const app = new Vue({
        el: '#el-index',
        data: function(){ 
          return {
            staffs: [],
            query: {
              name_cont: null,
              age_gteq: 0,
              age_lteq: 100,
              joined_on_gteq: null,
              joined_on_lteq: null
            }
          }
        },
        created: function(){
          this.search()
        },
        methods:{
          search: function(){
            axios.get('/api/staffs/search',{
              params:{
                q: this.query
              },
              paramsSerializer: function(params) {
                return Qs.stringify(params, {arrayFormat: 'brackets'})
              }
            })
            .then((response) => {
              console.log(response);
              this.staffs = response.data.staffs;
            })
            .catch((error) => {
              console.log(error);
            })
          }
        }
      })
    })
    
  • this.query 그대로 ransack 검색 쿼리입니다.
  • Qs.stringify에서 쿼리를 연관 배열로 변환합니다.
  • 반환 된 response 배열을 data에 저장하여 화면에 자동 반영됩니다.
  • 서버 측에서는 특별한 일은 하지 않고, 그대로 ransack를 사용하기만 하면 됩니다.

  • Gemfile
    + gem 'ransack'
    

    staffs_controller.rb
      # GET /api/staffs/searchs
      def search
        @q = Staff.ransack(search_params)
        @staffs = @q.result(distinct: true)
      end
      private
      def search_params
          params.require(:q).permit(:name_cont , :age_gteq , :age_lteq , :joined_on_gteq, :joined_on_lteq)
      end
    
    

    staffs/search.json.jbuilder
    json.staffs @staffs, partial: 'staffs/staff', as: :staff
    

    staffs/_staff.json.jbuilder
    json.extract! staff,
                  :id,
                  :name,
                  :age,
                  :joined_on,
                  :created_at,
                  :updated_at
    json.url staff_url(staff, format: :json)
    

    양식 만들기



    UI에는 Element-ui를 사용합니다.
    $ yarn add element-ui
    

    application.js
    import Vue from 'vue/dist/vue.esm'
    import axios from 'axios'
    import Qs from 'qs'
    +import ElementUI from 'element-ui'
    +import locale from 'element-ui/lib/locale/lang/ja'
    +import 'element-ui/lib/theme-default/index.css'
    +
    +Vue.use(ElementUI, { locale })
    +
    document.addEventListener('DOMContentLoaded', () => {
      const app = new Vue({
        el: '#el-index',
        data: function(){ 
          return {
            staffs: [],
            query: {
              name_cont: null,
              age_gteq: 0,
              age_lteq: 100,
              joined_on_gteq: null,
              joined_on_lteq: null
            }
          }
        },
        created: function(){
          this.search()
        },
        methods:{
    +      notify: function(msg){
    +        this.$notify({
    +          type: 'error',
    +          title: 'Error',
    +          message: msg
    +        });
    +      },
          search: function(){
            axios.get('/api/staffs/search',{
              params:{
                q: this.query
              },
              paramsSerializer: function(params) {
                return Qs.stringify(params, {arrayFormat: 'brackets'})
              }
            })
            .then((response) => {
              console.log(response);
              this.staffs = response.data.staffs;
            })
            .catch((error) => {
              console.log(error);
    +          this.notify(error.message);
            })
          }
        }
      })
    })
    
  • 일본어를 적용하려면 element-ui/lib/locale/lang/ja에서 import 한 locale을 설정하면 좋을 것 같습니다.

  • index.html.erb
    <div id="el-index">
      <h1>staffs</h1>
      <div class="search-form-static">
      <el-form ref="form" :model="query" label-width="120px">
        <el-form-item label="名前">
          <el-input v-model="query.name_cont" placeholder="input name"></el-input>
        </el-form-item>
        <el-form-item label="年齢">
          <el-col :span="11">
            <el-input-number v-model="query.age_gteq" :min="0" :max="150"></el-input-number>
          </el-col>
          <el-col class="line" :span="2">-</el-col>
          <el-col :span="11">
            <el-input-number v-model="query.age_lteq" :min="0" :max="150"></el-input-number>
          </el-col>
        </el-form-item>
        <el-form-item label="入社日">
          <el-col :span="11">
            <el-date-picker
              v-model="query.joined_on_gteq"
              type="date"
              placeholder="日時を選択してください">
            </el-date-picker>
          </el-col>
          <el-col class="line" :span="2">-</el-col>
          <el-col :span="11">
            <el-date-picker
              v-model="query.joined_on_lteq"
              type="date"
              placeholder="日時を選択してください">
            </el-date-picker>
          </el-col>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="search">search</el-button>
        </el-form-item>
      </el-form>
      </div>
      <el-table
        :data="staffs"
        height="400"
        stripe
        style="width: 100%">
        <el-table-column
          prop="name"
          sortable
          label="名前"
          width="180">
        </el-table-column>
        <el-table-column
          prop="age"
          sortable
          label="年齢"
          width="180">
        </el-table-column>
        <el-table-column
          prop="joined_on"
          sortable
          label="入社日">
        </el-table-column>
      </el-table>
    </div>
    
  • 참고: ぇ tp // 에멘 t. 네. 이오 / # / 엔우 S / 코 m 포넨 t

  • 테스트 데이터


  • faker를 사용하여 테스트 데이터를 만듭니다.

  • Gemfile
    + gem 'faker'
    

    seeds.rb
    10.times do
      Staff.create(
        name: Faker::Name.name,
        age: Faker::Number.between(18, 60),
        joined_on: Faker::Date.between(20.days.ago, Date.today)
      )
    end
    

    데모





    참고



    How to make AJAX calls in Rails 5.1 with or without jQuery
    Vue.js의 구성 요소 'Element'가 굉장했습니다.

    좋은 웹페이지 즐겨찾기