質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.37%

  • Ruby

    8780questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

  • Ruby on Rails

    8180questions

    Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

1つのカラムにデータを配列で入れるには?

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 196

Gr.

score 43

 1つのカラムに複数のテキストデータを入れたい

すごく初歩的な質問だと思います。

例)ユーザー登録フォームで"行ったことのある国"を入力してもらうケース
ユーザーAさんの行ったことのある国が「アメリカ」「イギリス」「中国」だったとし、そのデータをUserモデルのvisitedカラムに入れたいのですが、どうすればいいでしょうか。

そのデータをもとにやりたいことは...

  1. ユーザーAさんが何か国行ったことがあるかカウントしたい。
  2. "行ったことのある国"でユーザーの絞り込み検索がしたい。

この場合、あらかじめ選択肢で国名を設けておくと200近い選択肢が必要になりますよね。
かと言って、フォームに直接入力してもらおうとすると、「アメリカ、イギリス、中国」と書かれてはこれで一つの国になってしまいカウントできませんし、「アメリカ」に行ったことがある人としてユーザーAさんを取り出せません。

※質問の趣旨から逸れないために、ユーザーによる国名表記は別にガイド等を設けて一致しているものと仮定します。(「アメリカ」「アメリカ合衆国」「米国」など書き方は様々ですがみんな「アメリカ」と書いてくれる、などとここでは仮定する)

ユーザーAさんのvisitedカラムに "アメリカ", "イギリス", "中国" と入れられれば上記1,2は解決するのですが、それにはどうしたらいいのでしょうか。

 教えていただきたいこと

  • 「複数選択可の選択肢を設ける」がベストソリューションの場合、たぶんcheckboxを使用すると思うのですが、複数選択してカラムに配列でデータを送る書き方がわかりません。
  •  仮に登録できる上限を5か国までとし、text_fieldを5つ設け、それぞれをvisitedカラムに関連付けるとしたらどう書けばいいのでしょうか。

質問内容からお察しいただけるかと思いますが、全くの初心者ですのでお手柔らかにお願いします。

 例示用コード

コメントありがとうございます。
以下にコードを追記します。
たとえばチェックボックスで複数選択可にする場合、今の自分の知識では下記のように書くしかありません。

<%= form_for(@users) do |f| %>
 <label>アメリカ<%= f.check_box 'visited1', {}, "アメリカ" %></label>
 <label>イギリス<%= f.check_box 'visited2', {}, "イギリス" %></label>
 <label>中国<%= f.check_box 'visited3', {}, "中国" %></label>
 <%= f.submit %>
<% end %>


つまり、カラムをvisited1、visited2、visited3...と用意してそこに値を入れていくという何とも非効率なやり方です。選択肢が3つ程度ならこれでもいいのでしょうが、国名全てを選択肢にするとなると、これでは到底現実的ではなく、もっといい書き方があるはずです。

そこで、登録できる上限を5か国までとし、下記のようにtext_fieldを使ったほうがいいのかなと思ったのですが、、、

<%= form_for(@users) do |f| %>
 <p>行ったことのある国1</p>
 <p><%= f.text_field :visited %></p>
 <p>行ったことのある国2</p>
 <p><%= f.text_field :visited %></p>
 <p>行ったことのある国3</p>
 <p><%= f.text_field :visited %></p>
 <p>行ったことのある国4</p>
 <p><%= f.text_field :visited %></p>
 <p>行ったことのある国5</p>
 <p><%= f.text_field :visited %></p>
 <%= f.submit %>
<% end %>


これでは最後のフィールドに入れた値しか受け取れませんよね...
この5つのフィールドに入れられた値をvisitedカラムに "アメリカ", "イギリス", "中国" といった形で保存したいのです。

1つのtext_fieldで「ユーザーが単語をスペースで区切って入力すれば配列で保存できる」なんてことはできないのでしょうかね。

ド素人のレベルの低い質問で恐縮です。
コードのサンプルなど無くても、「〇〇使えば出来るよ」「こんな感じで書けば?」的なヒントだけでもいただければ自力で調べてみますので何とぞよろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • jun68ykt

    2018/09/09 11:11

    こんにちは。「ここまで作ってみたけど、意図どおりうまく動かなくて困ってる」とか、「ここまで出来たけど、ここから、こうする方法が分からない」といったような、今の段階を明らかにするような、作りかけのRailsアプリのコードはありますでしょうか?あれば、ご質問に追記をお願いいたします。

    キャンセル

回答 1

checkベストアンサー

+2

こんにちは。

質問への追記・修正依頼にお応え頂いてのソースコードの掲示、ありがとうございます。

「〇〇使えば出来るよ」「こんな感じで書けば?」的なヒントだけでもいただければ自力で調べてみますので

とありましたので、以下、「自分ならこう作るかな」というアイディアレベルの、あくまで私見になります。

(なお当方は、ふだんの業務時間の7〜8割がたフロントエンド開発に従事し、残り2〜3割をバックエンド開発のヘルプに入る的な立ち位置です。バックエンドは近年、Railsが多いです。)

 1.バックエンド開発

 1.1 国マスターテーブルの作成

  • Country モデルを作成し、 countriesテーブルに国のマスターデータを格納する。
  • 最低限、名前を入れる name カラムを用意する。
  • 元になるデータは、たとえば ISO 3166-1 の表などをスクレイピングさせて頂くなどして入手

例) countries テーブル

id name
1 アメリカ合衆国
2 中華人民共和国
3 オーストラリア
4 フランス

 1.2  users テーブルの visited カラムに入れる配列データの形式

  • visitedカラムの型は文字列で、countriesテーブルの id をCSV形式(カンマ区切りの文字列)で入れることにします。

例) 中国(country_id:2)とフランス(country_id:4)に行ったことのある鈴木(id=100)さんの場合

id name visited
100 鈴木 2,4

他の形式も考えられます。 たとえばJSONの配列形式にするのであれば、visitedには [2,4]という文字列が入ります。

 1.3 ユーザーの訪問したことのある国として、ある国を追加または削除するAPIの設計と実装

 1.3.1 設計

メソッドとURLはざっくり以下のようなものになるかと思います。

  • 鈴木さん(user_id:100)が行ったことのある国のリストに オーストラリア(country_id:3)を追加する。
POST /users/100/countries/3
  • 鈴木さん(user_id:100)が行ったことのある国のリストから オーストラリア(country_id:3)を削除する。
DELETE /users/100/countries/3

上記のURLとメソッド、さらにこれにパラメータの加わった、APIの設計は諸説意見の別れがちな所ではありますが、この回答では、とりあえず上記で進めます。

 1.3.2 実装

上記 1.3.1 のURLとメソッドからルーティングされる UsersController のアクションでは、以下を行うことになるでしょう。

 国の追加

  • user_id :100 のUserインスタンスを取得。 その visitedのCSVに 3 が無ければ追加したCSVを作って、この新しいCSV文字列でvisitedを更新

 国の除外

  • user_id : 100 のUserインスタンスを取得。 その visitedのCSVに 3 があればこれを除外したCSVを作って、この新しいCSV文字列でvisitedを更新

 2. フロントエンド開発

  • 先の1.3 で設計したAPIを使って、各チェックボックスの選択状態が変更されたら、すぐにDBに反映されるようなUIを想定します。

  • もちろん、すべてのチェックボックスについて「チェックする・しない」を入力し終わったあとに、「保存」ボタンをクリックしてもらって、各国の「訪問した or していない」を、まとめていっぺんに送る方法もありますが、この回答では、そのための説明は割愛します。

 2.1 チェックボックス

並べ方として最も簡単なのは、以下のように Country.order(:id) で得られる配列を単純にループして、チェックボックスを作成します。

アメリカ合衆国: <input type="checkbox" class="country_check" value="1" />
中華人民共和国: <input type="checkbox" class="country_check" value="2" />
オーストラリア: <input type="checkbox" class="country_check" value="3" />
フランス: <input type="checkbox" class="country_check" value="4" />
  • 各チェックボックスの classは “country_check” で統一し、value属性の値は country_id とします。

  • また、画面のどこかに user_id と ユーザー名を持っている hidden の<input> を書いておきます。以下は鈴木さん(user_id: 100)の場合です。

<input type="hidden" id="user_id" value="100" data-user-name="鈴木" />

 2.2 チェックボックスの変化からAPIをリクエスト

チェックボックスの選択状態の変化にあわせて、1.3 で設計、実装したAPIを呼ぶようにします。JQuery を使うとすると、以下のような感じです。(APIエラー時の処理等、細かいところは書いていません。あくまで概要を示すコードです。)

$(".country_check").on("change", function() {

  const countryId = $(this).val();  // country id の取得
  const userId = $("#user_id").val(); // ユーザーidの取得
  const userName = $("#user_id").data("user-name"); // ユーザー名の取得

  const apiUrl = `/users/${userId}/countries/${countryId}`; // APIのURL
  const method = $(this).prop("checked") ? "POST" : "DELETE"; // APIのメソッド

  fetch(apiUrl, { method })
    .then(res => {
        if(res.ok) {
          console.log(`${userName}さんの行ったことのある国が変更されました。`);
        }
     });
});

 
 
ざっと概要を示すと以上です。

それともう一点、この質問の主旨である「1つのカラムにデータを配列で入れるには?」から外れますが、補足を以下に書きます。

 補足: has_many :through関連付けの利用

  • User とCountry は Many to Many の関係なので、users と countries のインターセクションテーブル(たとえば visits という名前とします。)を作成し、これを介して 以下のように、has_many アソシエーションを追加するのが自然かなと思います。
class User < ActiveRecord::Base
  has_many :countries, through: :visits
end
class Country < ActiveRecord::Base
  has_many :users, through: :visits
end

Rails が用意してくれているモデル操作の仕組みをなるべく使う(いわゆる、"Rails Wayに乗る")と、やりたいことが楽に実現できることが多いので、私がこのRailsアプリを作るとしたら、上記のように has_many :through を使うことによって、「ユーザーが行ったことのある国」を表すことを考えると思います。

has_many :through関連付けの利用については以下をご参照ください。

以上参考になれば幸いです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/09/10 08:15

    jun68yktさん
    素晴らしい回答をありがとうございます!
    読みやすく、また具体的でとても参考になります。
    「has_many :throughで関連付けする」とか、「国名データを ISO 3166-1 の表などからスクレイピングする」とかそういった知識やアイデアもなかったため、知りたかったこと以上の知識が得られました。
    本当にありがとうございました!

    キャンセル

  • 2018/09/10 08:26

    Gr.さん
    お役にたてたようで、よかったです!

    キャンセル

同じタグがついた質問を見る

  • Ruby

    8780questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

  • Ruby on Rails

    8180questions

    Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。