LoginSignup
0
1

More than 5 years have passed since last update.

RoR 画面の入力値とモデルのバインディング

Posted at

始めに

画面の入力値とモデルのバインディングについて、実験的に実装してみます
Railsの便利系のGemは一切使わず、標準的なRubyのライブラリのみで実装しています

実行環境

JRuby 9.1.0
Rails 4.2.9

実装

モデル

exam_categori

:column_name=>"ID", :data_type=>"NUMBER"
:column_name=>"CATEGORY_CODE", :data_type=>"VARCHAR2"
:column_name=>"SAKUSEIYMD", :data_type=>"DATE"

exam

:column_name=>"ID", :data_type=>"NUMBER"
:column_name=>"WORD", :data_type=>"VARCHAR2"
:column_name=>"SENTENCE", :data_type=>"CLOB"
:column_name=>"WLEVEL", :data_type=>"NUMBER"
:column_name=>"SAKUSEIYMD", :data_type=>"DATE"
:column_name=>"RENBAN", :data_type=>"NUMBER"
※IDにはブラウザ側で振られたランダムな数字を設定する

画面

大雑把な仕様の説明

image.png

大雑把なinputフィールドのIDのつけ方について

image.png
→inputタグのid属性の命名規則を「model名#入力行数.モデルのカラム名」のようにする
Ralis側ではPOSTされたリクエストパラメタを

exam [
 {1=>[wlevel=value,word=value,sentence=value]},
 [2=>{wlevel=value,word=value,sentence=value}] ,
 [3=>{wlevel=value,word=value,sentence=value]} ,
]

のようなデータ構造に変換したい

Rails側の実装

exam_controller.rb
class ExamController< ApplicationController
protect_from_forgery :expect  => ["create"]
    def register
        a = params
        .to_a #--(1)
        .group_by do |k,v| --(2)
            str=k[/^.*#/]
            str.present? ?str.tr("#",""):"" 
        end
        .to_a--(3)
        .select{|k,v|k.present?}--(4)
        .map do|k,v|--(5)
            [k,v.group_by {|a,b|a.scan(/#(\d)/)[0]}]
        end
        puts a
        render text:""
  end
end

(1)リクエストパラメタ「params」を配列化する
(2)リクエストパラメタのキーで「モデル名#」にマッチングするものでグループ化する
(3)(2)の結果を配列化する
(4)(2)の結果でkeyがnilになるものを除外する
つまり、ここで、paramsに含まれていたコントローラやviewの情報が排除される
(5)(4)で変換した配列を["モデル名",{行数=>[画面の入力値の集まり]}]のデータ構造に変換する

実行結果

リクエストされたパラメタ値

Parameters: 
 {"exam_categori#1.category_code"=>"カテゴリ1", 
  "exam#1.word"=>"テスト1", "exam#1.sentence"=>"テスト1の説明", 
  "exam#1.wlevel"=>"1", "exam#2.word"=>"テスト2", 
  "exam#2.sentence"=>"テスト2の説明", "exam#2.wlevel"=>"2", 
  "exam#3.word"=>"テスト3", "exam#3.sentence"=>"テスト3の説明", 
  "exam#3.wlevel"=>"3", "id#1"=>"799454"}

rails側で変換した結果

[
    ["exam_categori", 
        {["1"]=>[["exam_categori#1.category_code", "カテゴリ1"]]}], 
    ["exam", 
        {["1"]=>[["exam#1.word", "テスト1"], 
                 ["exam#1.sentence", "テスト1の説明"], 
                 ["exam#1.wlevel", "1"]], 
         ["2"]=>[["exam#2.word", "テスト2"], 
                 ["exam#2.sentence", "テスト2の説明"], 
                 ["exam#2.wlevel", "2"]], 
         ["3"]=>[["exam#3.word", "テスト3"], 
                 ["exam#3.sentence", "テスト3の説明"], 
                 ["exam#3.wlevel", "3"]]}]
    ["id", 
         {["1"]=>[["id#1", "799454"]]}]
]

参考:画面側の実装

exam.html
<!DOCTYPE html>

<script>
function doPost(){
    var id = Math.floor(Math.random () * 1000000) 
    var param = _g()
    .concat(
       [`id#1=${id}`])
    .join('&')
    commute('http://localhost:3000/exam/register/',param)
}
function commute(url,param){
    var req = new XMLHttpRequest();
    req.open('POST',url , true);
    req.setRequestHeader('content-type',
    'application/x-www-form-urlencoded;charset=UTF-8');
    console.log(param)
    req.send(param);
    req.onload =  _r(req,
        function(){_t('display',req.responseText );});
}
function _r(req,caller){
  return function (event){
    if (req.readyState === 4 && req.status === 200) 
      caller();
  };
}
function _f(str){
    return document.getElementById(str).value;
}
function _t(str,text){
    return document.getElementById(str).innerText=text;
}
function _k(str){
   return Object.keys(document.getElementsByTagName(str))
}
function _g(){
    console.log(_k('input'))
    return _k('input')
    .filter(a=>isNaN(a))
    .map(a=>`${a}=${_f(a)}`)
}


</script>

<body>
<div style="position:relative;left:7pt;padding:10pt;border: 1pt solid #2cbf88;width:600pt">
  <div style="position:relative;left:7pt;padding:10pt;border: 1pt solid #2cbf88;width:400pt">
      カテゴリ:
      <div style="position:relative;left:5pt;padding:5pt"> 
          <input type='text'id='exam_categori#1.category_code' size='50'>
      </div>
  </div>
  <div style="position:relative;left:7pt;padding:5pt;"></div>  
  <div style="position:relative;left:7pt;padding:10pt;border: 1pt solid #2cbf88;width:500pt">
    <div style="position:relative;left:5pt;padding:5pt">
        レベル1:
        <input type='text'id='exam#1.word' size='10'>
        <input type='text'id='exam#1.sentence' size='50'>
        <input type='hidden' id='exam#1.wlevel' value="1">
    </div>
    <div style="position:relative;left:5pt;padding:5pt">
        レベル2:
        <input type='text'id='exam#2.word' size='10'>
        <input type='text'id='exam#2.sentence' size='50'>
        <input type='hidden' id='exam#2.wlevel' value="2">
    </div>
    <div style="position:relative;left:5pt;padding:5pt">
        レベル3:
        <input type='text'id='exam#3.word' size='10'>
        <input type='text'id='exam#3.sentence' size='50'>
        <input type='hidden' id='exam#3.wlevel' value="3">
    </div>
  </div>
</div>
<input type='button' onclick='doPost();' value="登録">
<div id='display'></div>
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1