20190530のRailsに関する記事は17件です。

今日のリファクタリング -1

お腹ぐるぐるヨーグルト
どうも k1y0です。初めてのqiita投稿。

今日のキニナルコード

before_action :set_content #@content

def show
  if params[:type] == 'programming'
    @title = '速習 プログラミング!'
    @text  = @content.programming_text
  elsif params[:type] == 'food'
    @title = '美味しい焼肉屋さん'
    @text  = @content.food_text
  elsif params[:type] == 'money'
    @title = '爆速で100億稼ぐ方法'
    @text  = @content.money_text
  end
end

こんなコードがありました。

どう変更したか

#before省略
def show
  @title, @text =
  case params[:type]
  when 'programming'
    '速習 プログラミング!', @content.programming_text
  when 'food'
    '美味しい焼肉屋さん', @content.food_text
  when 'money'
    '爆速で100億稼ぐ方法', @content.money_text
  end
end

課題

typeごとにhashとか作ってkeyで受け取った方がわかりやすそう。rubyむずかしい

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby on Rails】resourcesで作られるルーティングの表記を作るアプリを作った。

タイトル見て「は?」って思った方もいるかなと思います。

Railsでアプリを作成する際に欠かせないルーティングですが、そこには resources っていう便利なメソッドがあります。

例えば、routes.rbに

routes.rb
resources :users

って書くと

Prefix Verb URI Pattern Controller#Action
users  GET /users(.:format) users#index
POST /users(.:format) users#create
new_user  GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE  /users/:id(.:format) users#destroy

これらが一気に作られるわけですよ。(ああ便利)

ただ、たまに resources を使いたくない人とか使えない場合とかあったりなかったりします。

例えば、URI Patteren のところに users ではないコントローラーを使いたいときとか。

そんなとき用に完全個人用に Rails でアプリ作りました。
(個人用にサクッと作ったので見たらわかるやっすいやつやん)

↓↓↓↓↓↓↓↓これです↓↓↓↓↓↓↓↓
https://resourcesrouting.herokuapp.com/

使い方

Name と Name2 にそれぞれ何かしら文字列を入れて "Create Home" ボタン押すだけ。
スクリーンショット 2019-05-30 20.39.57.png

下のように出力されます。
スクリーンショット 2019-05-30 20.40.05.png

あとはコピってペーストするだけ。

正直ワンパターンだけしかこんな今年ないならいらないですが、いくつもルーティングをこんな感じにする際は多少楽になるかなって思います。

後記

実際これ作るのに30分もかかってないですが、こんなの作ってる暇あったら素直に手打ちできたなと思っています(笑)

まぁでも、楽しいんでいいです(¬ω¬)‬b

ちなみにDBもセッションもなにも使ってないので何かが保存されることはないです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】Active Storage + S3 + Active JobでGoogle Cloud Visionセーフサーチ

個人開発のWebアプリまちかどルートv6.0rc6への実装メモです。

Amazon S3に画像をダイレクトアップロード

Railsガイドをもとに実装しました。

セーフサーチを実装

前回の記事のとおりです。

【Rails】Active Storage環境下でGoogle Cloud Visionのセーフサーチを実装

S3アップロード画像のパブリックURLを取得

こちらの記事を参考にしました。

Rails ActiveStorage で PUBLIC な URL を表示する

セーフサーチを非同期処理化

※controllerのコードは省略します

model

post.rb
    has_one_attached :image
    after_commit :annotate_self, on: [:create, :update]

    def annotate_self
        if image.attached?
            ImageAnnotateJob.set(wait: 10.second).perform_later(self)
        end
    end

postの新規投稿もしくは編集のときに画像imageが添付されていたらImageAnnotateJobというActive Jobのキューを走らせます。10秒後に走らすようセットした理由は、Amazon S3へのアップロード完了までのタイムラグが発生するかなと思ったからです。

job

image_annotate_job.rb
class ImageAnnotateJob < ApplicationJob
  queue_as :second

  def perform(target)

    tempfile = target.image.attachment.service.send(:object_for, target.image.key).public_url

    require "google/cloud/vision"
    image_annotator = Google::Cloud::Vision::ImageAnnotator.new
    response = image_annotator.safe_search_detection image: tempfile
    response.responses.each do |res|
    safe_search = res.safe_search_annotation
      if safe_search.adult.to_s == "VERY_LIKELY" || safe_search.adult.to_s == "LIKELY"
        target.destroy
        return
      elsif safe_search.violence.to_s == "VERY_LIKELY" || safe_search.violence.to_s == "LIKELY"
        target.destroy
        return
      elsif safe_search.medical.to_s == "VERY_LIKELY" || safe_search.medical.to_s == "LIKELY"
        target.destroy
        return
      end
    end

  end

end

いったんtempfileにS3アップロード画像のパブリックURLを格納。それをGoogle Cloud Visionのセーフサーチにかけます。このコードはすべてActive Jobによってバックグラウンド(非同期)処理されます。もし不適切な画像と判断されれば投稿そのものを削除する流れです。

Sidekiq

config\sidekiq.yml
:concurrency: 5
:queues:
  - [default, 7]
  - [second, 5]

じぶんはActive JobのライブラリとしてSidekiqを使用しています。上記image_annotate_job.rbqueue_as :secondによってキューが処理される優先順位を設定しました。

あとがき

駆け足ですが以上です。Google Cloud Visionのセーフサーチは高精度ですがレスポンスに1~2秒ほど要するため、そのぶん前回の記事のような同期処理だと投稿完了までにユーザーを待たせてしまううえ、サーバーサイドに負荷がかかります。今回の記事はそれらの課題を解決するものとなります。

また、苦労したのがS3アップロード画像のパブリックURLを取得する部分でした。url_forrails_blob_urlといったActive Storageのメソッドを使うと時限的なものorリダイレクトされるURLしか取得できずセーフサーチにかけても「そんな画像はありませんよ」と言われてしまいます。

というわけで試行錯誤を経たおかげでよりレスポンス性とセキュリティ性を兼ね備えた画像投稿機能を実装できました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[jQuery/Rails] Uncaught TypeError: t.modal is not a function

前提

Rails5.2

エラー内容

SummernoteのWYSIWYGエディターを使って、写真投稿をする機能を実装しようとしたら、エディターのImageタブをクリックしても、画像挿入のウィンドウが表示されない(エディター)、という問題。

Google Chromeのデベロッパーツール(Shift+Command+c)でエラー内容を確認すると、以下のエラーが発生する。

Uncaught TypeError: t.modal is not a function
at Object.showDialog.........
at Object.<anonymous>........

色々ネットで調べると、このエラーメッセージは、 
Uncaught TypeError: $(...).modal is not a function
直訳:「$(...).modalはfunctionではありません」
意訳:「.modal()なんて関数は存在しない」
っていう意味らしい。このエラーは、JavaScriptのエラーなので、railsとかrubyではなく、一番疑わしいのは、「自身のコード内に該当するJavaScriptの記述が存在するかどうか」らしい。

よくわからんけど、要は、JavaScriptが怪しいらしい!!!

とりあえず、自分のjsが記述されている、javascripts/application.jsを見に行く。

よ〜く見ると、jqueryが3つも記述されている。これが怪しいかも。。。
//= require jquery2
//= require jquery
//= require jquery_ujs

assets/javascripts/application.js
//= require jquery2 ← この子
//= require rails-ujs
//= require popper
//= require bootstrap
//= require bootstrap-sprockets
//= require jquery ← この子
//= require jquery_ujs ← この子
//= require_tree .
//= require toastr
//= require jquery-ui
//= require tag-it
//= require summernote/summernote-bs4.min
//= require summernote/lang/summernote-ja-JP
//= require summernote-init
//= require activestorage
// = require turbolinks

解決策

railsでのjqueryの記述の仕方について、原点に戻る。
【リンク】rails/jquery-rails

すると、記述方法に以下の通り記載されている。

Installation
If you are running Rails 5.1 and up, and if you have included //= require rails-ujs, then jquery_ujs is not needed anymore. You can just add:
//= require jquery
If you want to use jQuery 2, you can require jquery2 instead:
//= require jquery2
//= require jquery_ujs

と記載されている。

つまり、次の2点によって、エラーが発生していた。
1. Rails5.1以降は、rails-ujsがあれば、//= require jquery_ujsは不要
2. //= require jquery2使ってるなら、//= require jqueryは不要

よって、次の2つを削除して、
//= require jquery
//= require jquery_ujs

次の2つだけを残せばOKでした!!!

assets/javascripts/application.js
//= require jquery2 ← キープ
//= require rails-ujs ← キープ

以上。

関連リンク

rails/jquery-rails

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails OAuth::Unauthorized というエラー出たら

OAuth::Unauthorized エラー

Railsで現在サービスを開発しているホリカワ です。

本番環境でツイッター経由ログインしようとすると、上記のエラーが出ました。
スクリーンショット 2019-05-28 21_0.14.35.png

原因としては

①CallbackURLの設定ミス
②Twitter API key関連の設定ミス

が多いかとは思います。(これ以外にもたくさんありそう)

解決方法

僕の場合は①でした。

結論からいうと、config/initializers/devise.rbに設定を加えると解決しました。

config/initializers/devise.rb
config.omniauth :twitter, "twiiter api key", "twitter secret key"

scope: 'email', callback_url: 'example.com/auth/twitter/callback'
↑を追加

config/initializers/devise.rb
config.omniauth :twitter, "twiiter api key", "twitter secret key", scope: 'email', callback_url: 'example.com/auth/twitter/callback'

わかったこと

このほかのエラーの原因として、本番環境の場合はhttps://でないとダメみたいです。

また、twitter dev のアプリの設定で、callback_urlが間違っていないかはrails routesで確認してみましょう。

user_twitter_omniauth_callback GET|POST /users/auth/twitter/callback(.:format

終わりに

OAuth::Unauthorized は調べてみた感じだといくつかの要因が考えられそうです。
こちらの記事が解決のお手伝いになればと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails Missing host to link to! のエラーが出た時 

Missing host to link to! Please provide the :host parameter, set default_url_options[:host]

Railsでサービスを開発しているホリカワ です。

ついに開発環境で一通り終え、本番環境にデプロイしたら上記のようなエラーが出ました。

ようは確認URLを渡すメールが送れない、というエラーです。

解決方法

https://easyramble.com/missing-host-to-link-to.html
↑こちら参考にさせていただきました、ありがとうございます。

上記のエラーは
「hostが見つからないので、default_url_options[:host]を指定してくれ」
ということなので、以下のようにすれば解決します。

config/production.rb
...
config.action_mailer.default_url_options = { host: 'example.com'}
...
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

STIとポリモーフィックを利用したコメント機能の作成

はじめに

インターン先でSTIとポリモーフィックを利用したコメント機能を作成したときに
自分が求めてる情報が出てこなかったのと
ハマったことがいくつかあるのでメモ代わりに残していこうと思います:relieved:

ポリモーフィックやSTIについては
Railsのポリモーフィック関連とはなんなのか
みんなRailsのSTIを誤解してないか!?
などがとても丁寧でわかりやすく参考になります:open_hands:

今回は設計やコード中心なので概念などはそちらで理解していただければと思います:relaxed:
私も未熟なところがたくさんあるので、指摘等あれば教えていただけると嬉しいです:relaxed:

設計について

今回の設計はざっとこんな感じです。
(いろいろ省いて主要部分だけの実装を行っていきます:man_tone1:)

ER図 (1).png

1つのcommentsテーブルに2種類のテーブルがSTIで継承されており
taskかprojectのどちらかが紐づくような設計となっております!:eyes:
常にprojectとtaskに紐づくcommentを作るわけではないので
projectとtaskからのびるcommentへのリレーションは点線で記述しました:fist:
(正しい書き方があるのかわからなかったです:sweat:

実装

早速実装に入っていきます!

テーブルの作成

commentsとtasksとprojectsテーブルの作成を行っていきます:relieved:
commentsテーブルにはSTIのためのtypeを作成し
ポリモーフィックのためのcommentable_typecommentable_idという〇〇_typeと〇〇_idというカラムも作ります:punch:

$ rails g model Comment content:string type:string commentable_type:string commentable_id:integer
$ rails g model Task title:string content:string 
$ rails g model Project name:string 

モデルの設定

モデルのディレクトリ改造は写真のようにcommentをtaskとprojectが継承するように作成します:runner_tone1:
スクリーンショット 2019-05-29 18.01.28.png

こうすることによりSTIを行うことができます:raised_hands:
次はモデルにポリモーフィックなどの設定を行っていきます:point_up:

comment.rb
class Comment < ApplicationRecord
  belongs_to :commentable, polymorphic: true
end
project.rb
class Project < ApplicationRecord
  has_many :comments, class_name: 'Comment::Project', as: :commentable, dependent: :destroy
end
task.rb
class Task < ApplicationRecord
  has_many :comments, class_name: 'Comment::Task', as: :commentable, dependent: :destroy
end

commentを継承しているprojectとtaskは

.rb
class Comment::Task < Comment
end
.rb
class Comment::Project < Comment
end

と記述することにより、commentを継承してくれます:astonished:
モデルに記述することは以上です:slight_smile:

ポリモーフィックとSTIができているかの確認

この時点でrails consoleで以下のコマンドたちを打ってみてください!:point_down:

 pry(main)> Comment::Task.new
=> #<Comment::Task:0x00007fbf75f1e668 id: nil, type: "Comment::Task", commentable_type: nil, commentable_id: nil>
 pry(main)> @task = Task.create(title: "test", content: "test")
 pry(main)> @task.comments.build
=> #<Comment::Task:0x00007fbf7b0ba418 id: nil, type: "Comment::Task", commentable_type: "Task", commentable_id: 4, user_id: nil, content: nil, created_at: nil, updated_at: nil>

typeには継承しているmodelが入っていおり
commentable_typeにはcommentに紐づくmodelが入り
commentable_idにはcommentに紐づくidが入っております:thumbsup:
こうすることにより、commentという1つのモデルに2つのうちどちらか1つのモデルに紐づけることができます:clap:
この3つのカラムが作成できていたら、ポリモーフィックとSTIができています:sparkles:

ルーティングとcontrollerの設定

routes.rb
Rails.application.routes.draw do
  resources :tasks do
    resources :comments, only: [:create], controller: 'task/comments'
  end
  resources :projects do
    resources :comments, only: [:create], controller: 'project/comments'
  end
end

コントローラーはタスク用とプロジェクト用で分けて作ります:woman_tone1:
スクリーンショット 2019-05-30 12.44.55.png

タスクのコメント機能の作成

ここからはタスクのコメント機能について作成していきます:muscle:
まずはcontrollerです:open_hands:

tasks/show.html
@comment = Comment::Task.new

Comment::Taskのインスタンスを作成してtasksの詳細ページに投稿画面を作成します:v:

tasks/show.html.erb
<%= form_for @comment, url: task_comments_path(task_id: @task.id) do |f| %>
  <%= f.text_area :content %>
  <%= hidden_field_tag :type, @comment.type %>
  <%= f.submit 'コメントを投稿する' %>
<% end %>

タスクを継承しているコメントControllerでcreateを行っていきます:point_down:

controllers/task/comment_controller.rb
  def create
    @comment = @task.comments.build(comment_params)
    @comment.save
    redirect_to task_path(@task)
  end

  private

  def comment_params
    params.require(params[:type].underscore.gsub('/', '_').to_sym).permit(:content)
  end

パラメーターの受け取り方はStrong Parametersを動的に設定を参考にしました:dancer:

実はこれだけでもうコメントの作成はできております!:clap:

終わりに

STIやポリモーフィック、最初全然理解は出来なかったですが、実際に手を動かすことで少し理解できたような気がします。
今はtaskとprojectにしか紐付かないのですが、もっといろんなモデルに紐づくものだと
紐づくために必要な外部キーを増やさなくて良かったり
新しくコメントに関するテーブルを作らなくていいので便利だと感じました。
でもなぜそういう使い方をしている記事がヒットしなかったんだろうという疑問が残りました。
最後まで見ていただきありがとうございました!
ご指摘あればどしどしおまちしております〜!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}

+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

mac で rails new した後の bundle install 時に ffi 1.11.0 のインストールが失敗したのでバージョン固定で解決

バージョン

名前 バージョン
macOS 10.13.6
ruby 2.3.7p456 (2018-03-28 revision 63024) [universal.x86_64-darwin17]
rails 5.2.3

起きたエラー内容

 $ bundle exec rails new ../sample
      create  
      create  README.md
      create  Rakefile
      create  .ruby-version
      create  config.ru
      create  .gitignore
      create  Gemfile

(略)


Fetching gem metadata from https://rubygems.org/............
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Fetching rake 12.3.2


Your user account isn't allowed to install to the system RubyGems.
  You can cancel this installation and run:

      bundle install --path vendor/bundle

  to install the gems into ./vendor/bundle/, or you can enter your password
  and install the bundled gems to RubyGems using sudo.

  Password: 
Installing rake 12.3.2
Fetching concurrent-ruby 1.1.5
Installing concurrent-ruby 1.1.5

(略)

Fetching coffee-rails 4.2.2
Installing coffee-rails 4.2.2
Fetching ffi 1.11.0
Installing ffi 1.11.0 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c
/System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/bin/ruby -r ./siteconf20190519-47252-1at7a63.rb extconf.rb
checking for ffi.h... no
checking for ffi.h in /usr/local/include,/usr/include/ffi... yes
checking for ffi_call() in -lffi... yes
checking for ffi_closure_alloc()... no
checking for shlwapi.h... no
checking for rb_thread_call_without_gvl()... yes
checking for ruby_native_thread_p()... yes
checking for ruby_thread_has_gvl_p()... yes
creating extconf.h
creating Makefile

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/extensions/universal-darwin-17/2.3.0/ffi-1.11.0/mkmf.log

current directory: /private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c
make "DESTDIR=" clean

current directory: /private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c
make "DESTDIR="
mkdir -p "/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c"/libffi-i386; (if [ ! -f
"/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c/libffi"/configure ]; then echo "Running autoreconf for libffi"; cd
"/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c/libffi" && /bin/sh
/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c/libffi/autogen.sh > /dev/null; fi); (if [ ! -f
"/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c"/libffi-i386/Makefile ]; then echo "Configuring libffi for i386"; cd
"/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c"/libffi-i386 && env CC=" xcrun clang" CFLAGS="-arch i386 " LDFLAGS="-arch i386"
"/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c/libffi"/configure --disable-static --with-pic=yes --disable-dependency-tracking --disable-docs
--host=i386-apple-darwin > /dev/null; fi); env MACOSX_DEPLOYMENT_TARGET=10.4 /Applications/Xcode.app/Contents/Developer/usr/bin/make -C
"/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c"/libffi-i386

(略)

libtool: link: ranlib .libs/libffi_convenience.a
libtool: link: ( cd ".libs" && rm -f "libffi_convenience.la" && ln -s "../libffi_convenience.la" "libffi_convenience.la" )
/bin/sh ./libtool  --tag=CC   --mode=link xcrun clang  -arch i386  -Wall -fexceptions -no-undefined -version-info `grep -v '^#'
/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c/libffi/libtool-version`   '-arch' 'i386'  -arch i386 -o libffi.la -rpath /usr/local/lib src/prep_cif.lo
src/types.lo src/raw_api.lo src/java_raw_api.lo src/closures.lo  src/x86/ffi.lo src/x86/sysv.lo
libtool: link:  xcrun clang -dynamiclib  -o .libs/libffi.7.dylib  src/.libs/prep_cif.o src/.libs/types.o src/.libs/raw_api.o src/.libs/java_raw_api.o src/.libs/closures.o src/x86/.libs/ffi.o src/x86/.libs/sysv.o    -arch i386 -arch
i386 -arch i386   -install_name  /usr/local/lib/libffi.7.dylib -compatibility_version 9 -current_version 9.0 -Wl,-single_module
ld: warning: The i386 architecture is deprecated for macOS (remove from the Xcode build setting: ARCHS)
Undefined symbols for architecture i386:
  "___x86.get_pc_thunk.bx", referenced from:
      _ffi_call_i386 in sysv.o
      _ffi_closure_raw_SYSV in sysv.o
      _ffi_closure_raw_THISCALL in sysv.o
  "___x86.get_pc_thunk.dx", referenced from:
      _ffi_closure_i386 in sysv.o
      _ffi_closure_STDCALL in sysv.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[3]: *** [libffi.la] Error 1
make[2]: *** [all-recursive] Error 1
make[1]: *** [all] Error 2
make: *** ["/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c"/libffi-i386/.libs/libffi_convenience.a] Error 2

make failed, exit code 2

Gem files will remain installed in /var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0 for inspection.
Results logged to /var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/extensions/universal-darwin-17/2.3.0/ffi-1.11.0/gem_make.out

An error occurred while installing ffi (1.11.0), and Bundler cannot continue.
Make sure that `gem install ffi -v '1.11.0'` succeeds before bundling.

In Gemfile:
  spring-watcher-listen was resolved to 2.0.1, which depends on
    listen was resolved to 3.1.5, which depends on
      rb-inotify was resolved to 0.10.0, which depends on
        ffi
         run  bundle exec spring binstub --all
bundler: command not found: spring
Install missing gem executables with `bundle install`
$

macOS が 10.13.6 なのがきっといけないのだろうと思うが、そこじゃない場所で解決を試みる。

解決後に Gemfile.lock を見ると、 ffi の依存指定は一箇所のみで、こうなっていた。

    rb-inotify (0.10.0)                                                                                                
      ffi (~> 1.0)

ffi (~> 1.0) とあるので、 ffi1.x の最新版を取ろうとして、それがインストールできていない。

解決方法

~> 1.0 ということは 1.11.0 が必要なわけじゃないはずので、 Gemfile を書き換えて、インストールできるバージョンに固定した。 1.9.21 は、あくまで例です

gem 'ffi', '= 1.9.21'

(これは要らないかもしれない) 事前にインストールしておく。

$ sudo gem install ffi -v '1.9.21'
Fetching: ffi-1.9.21.gem (100%)
Building native extensions.  This could take a while...
Successfully installed ffi-1.9.21
Parsing documentation for ffi-1.9.21
Installing ri documentation for ffi-1.9.21
Done installing documentation for ffi after 3 seconds
1 gem installed
$

で、改めて bundle install

$ bundle install --path vendor/bundle
The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`.
Fetching gem metadata from https://rubygems.org/............
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Using rake 12.3.2
Using concurrent-ruby 1.1.5

(略)

Using railties 5.2.3
Using coffee-rails 4.2.2
Fetching ffi 1.9.21
Installing ffi 1.9.21 with native extensions

うまくいった

バージョンの選び方

ffi 1.9.21 を選ぶべきだというわけではないのですが、あらかじめ mac 側にインストールしてある可能性(他の ruby プログラムを動かすためにインストールしたことがあった、など)を考えれば、たとえば gem list で調べればインストール可能なバージョンがわかるはず

$ gem list ffi

*** LOCAL GEMS ***

ffi (1.9.21)
public_suffix (3.0.3)

それ以外では、 https://rubygems.org/gems/ffi/versions を見て、一つ前のバージョンの最新を選ぶと良いと思います。今回だと、失敗したのは 1.11.0 なので、 1.10.x の中での最新の 1.10.0 を試す、それでもダメなら 1.9.25 を試す、...を繰り返す、など。

時間がある人は、もちろん原因を特定してそれが解決できる最新のバージョンを選びましょう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RSpec 設定

RSpec導入のための備忘録です。

Gemfile

Gemfile
source 'https://rubygems.org'
ruby '2.6.3'
gem 'rails', '~> 6.0.0.rc1'

group :development, :test do
  gem 'factory_bot_rails'
end

group :test do
  gem 'capybara'
  gem 'selenium-webdriver'
  gem 'webdrivers'
  gem 'rspec-rails'
end
config/application.rb
require_relative 'boot'
require 'rails/all'
Bundler.require(*Rails.groups)

module Taskleaf
  class Application < Rails::Application
    config.load_defaults 6.0

    config.generators do |g|
      g.test_framework :rspec,
                       fixtures: true,
                       view_specs: false,
                       helper_specs: false,
                       routing_specs: false,
                       controller_specs: false,
                       request_specs: true,
                       system_specs: true
    end
  end
end
$ rm -rf ./test
$ rails g rspec:install
spec/spec_helper.rb
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
require 'capybara/rspec'

RSpec.configure do |config|
  config.before(:each, type: :system) do
    driven_by :selenium_chrome_headless
  end

  # rspec-expectations config goes here. You can use an alternate
  # assertion/expectation library such as wrong or the stdlib/minitest
  # assertions if you prefer.
  config.expect_with :rspec do |expectations|
spec/rails_helper.rb
# コメントされているので、コメントを外す
# spec/support以下に、いろいろファイルを置けるようになる
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }


RSpec.configure do |config|
  # テスト中に、FactoryBot.create(:user) ではなく、create(:user) と書けるようになる。
  config.include FactoryBot::Syntax::Methods
end
spec/support/login_support.rb
module LoginSupport
  # 利用者がログインする
  def login_as(user)
    visit root_path
    click_link "Sign in"
    fill_in "Email", with: user.email
    fill_in "Password", with: user.password
    click_button "Log in"
  end
end

# RSpecの設定 LoginSupport をinclude
RSpec.configure do |config|
  config.include LoginSupport
end

RSpecのレポートを見やすく

.rspec
--require spec_helper
--format documentation

ファクトリ追加

rails g factory_bot:model user
spec/factories/users.rb
FactoryBot.define do
  factory :user do
    name { '太郎' }
    sequence(:email) { |n| "user#{n}@example.com" } # 連番
    password { 'password' }
  end
end

スペック作成

# rails g rspec:system users # ジェネレータ無いので手動
rails g rspec:request users
rails g rspec:model users

参考

使い方

使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」
使えるRSpec入門・その2「使用頻度の高いマッチャを使いこなす」
使えるRSpec入門・その3「ゼロからわかるモックを使ったテストの書き方」
使えるRSpec入門・その4「どんなブラウザ操作も自由自在!逆引きCapybara大辞典」
rspec-rails 3.7の新機能!System Specを使ってみた

書籍

Everyday Rails - RSpecによるRailsテスト入門
Everyday Rails
現場で使える Ruby on Rails 5速習実践ガイド

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails new の手順メモ

メモ: アプリケーションを作るときに必要な Gemfile と、アプリケーションで使う Gemfile は別でよい。

Rails アプリケーション作成用のプロジェクトを作る

Gemfile

rails_generator みたいなディレクトリを作って、そこに Gemfile って名前のファイルを置く。内容は下記

Gemfile
# frozen_string_literal: true
source 'https://rubygems.org'

gem 'rails'

bundle install

デバッグ用なので path を指定する

$ bundle install --path vendor/bundle

こんな感じになるはず

$ ls
vendor
Gemfile
Gemfile.lock
$

rails new

ディレクトリを指定して rails new をする。今回は

-+- (root)
 |- rails_generator (今操作していたディレクトリ)
 `- sample

となるように下記を実行してみる。

$ bundle exec rails new ../sample

終わったら、 rails_generator 配下は消して良い

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】個人開発のアプリに5,000万円の交渉相手が現れました

個人開発のWebアプリまちかどルート

驚いたことに5,000万円の交渉話が飛び込んできました。

まだ交渉中ではありますが、ここに至る1年弱の所感をまとめたいと思いました。

RubyとRailsに入門して1年弱

プログラミングを学んだのは、40代でセミリタイア&山奥で隠居生活するようになってからというもの、新たなたしなみのひとつにしようと思ったのがきっかけです。

ソーシャルな隠居の、新たな“たしなみ”。プログラミングをはじめました

アイデアがどう生まれたか

世間と隔絶されずより一層ひととの関係性を高める自称 ソーシャルな隠居生活では、じぶんの時間がたくさん持てます。余白の時間に「あ、こんな機能を作ってみようかな」というアイデアがふと生まれやすいです。

アイデアとは、ひねり出すものではなく、それまで興味の赴くまま得てきた数多くのインプットと行動から余白の時間にふと思いつくものなのでしょうか。

よくローカル環境構築などと言いますが、ノートPC上だけでなく自身の環境構築も大事なんだと思いました。そういう意味ではじぶんの環境構築は恵まれていたかもしれません。

生活への変化

プログラミングをたしなみのひとつにしたおかげで、そうした余白の時間が充実したものになりました。

たとえばカフェなどで思いがけず待ち時間が長くなったとしても、ふとアイデアを思いついたらノートPCを開き、コードに落とし込みます。

いままで持て余していた時間が楽しいものとなりました。

どう学んできたか

書籍を読んだりスクールに通うということをしていません。ほとんどが必要に応じてインターネットで調べるという独学スタイルです。そのせいか基本的な知識がところどころ抜けているように思います。

反面、基本的な知識がないおかげなのか、参考文献をそのまま写すのではなく「もしかしてこんなふうに書けば動くのかな」という感じでコードを自由奔放に書き換えたりするんですけど、それが本当に動くとうれしいですね。いわゆる論理的思考が鍛えられているのでしょうか。

開発を続けられた理由

オープンソースのSNS「Mastodon」に触れていたことが大きかったと思います。だいぶお手本にさせていただきましたし、APIで連携することで個人開発の幅が広がりました。

Mastodonが日本に普及して2年。インスタンス運営と連携アプリの開発が楽しい

これから

5,000万円の交渉の成否はこれからのことなのでさておき、じぶんの生活を経済的というよりひととの関係性や精神的に豊かにするための趣味の個人開発ですから飽きるまで続けていこうと思います。

なによりも、スタートアップやエンジニア関係のつながりがこれまで以上に増えたことがうれしいです。やはりコミュニティとして日常的に学びあうことが、成長のスピードを加速させるんでしょうね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[初心者]テストコードを書く際の原則

テストコードとは?

テストコードとは、本番環境に実装する前に、各メソッドがしっかりと自分が期待した値を取得し、保存しているのか確認することを指します。

もしなにもテストせずに本番環境に実装してしまったら、ユーザーからの苦情があり、サーバーを止めて修正しないといけないですよね??
それらの原因が結果的に、損失だったり、ユーザーの評価を下げてしまうことになる可能性があります?

今回はテストコードを書く際の大切な原則について書いていきたいと思います!!

①各exampleで期待する値は1つだけ

期待する値を2つ以上含めてしまうと、どちらのエクスペクテーションでエラーが出たのか判別できず、正確なテストができないため、1つだけにしておきましょう!!

※エクスペクテーション(予想、期待、切望、待望)

②期待する結果をはっきりと分かりやすく記述

明快な記述にすることで、自身の確認やメンバーとの共有、顧客への仕様説明が楽になります。
結果としてコミュニケーションミスが低下し、スムーズに仕事を進めることができます。

もし分かりづらい記述だったら、一々相手に確認をしてテストするという無駄な時間が生まれますよね?

③起きて欲しいことと起きてほしくないこと両方をテストする

これはどちらもテストで予期せぬ動作が残るのを防ぐためにどっちも行います!!

そうすればエラー発生率の低下に繋がると思っています?

④境界値をテストする

例えば、パスワード登録の際に8文字以上を保存するとしましょう。
テストする際には、8文字以上保存されているかの確認と、逆に7文字以下のパスワードは保存されていないかテストをする必要があります。
よくバリデーションとかに使われるので、しっかりチェックする必要がありますね?

可読性を考えつつ、適度にDRYする

DRYとはDon't Repeat Yourselfの略になります。
テストコードにおいて何よりも相手に伝わる分かりやすさが大切です。
分かりづらくなってテストの見落としが起きるよりマシだと思いませんか?

最後に

本番環境前には必ずテストコードを書き、
ちゃんとメソッドが定義されているのか、
値がしっかり取得されているのかを確認してしっかりとしたアプリケーションを作っていきましょう!!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【スクール生】12日目:テストコードを書く際の原則

テストコードとは?

テストコードとは、本番環境に実装する前に、各メソッドがしっかりと自分が期待した値を取得し、保存しているのか確認することを指します。

もしなにもテストせずに本番環境に実装してしまったら、ユーザーからの苦情があり、サーバーを止めて修正しないといけないですよね??
それらの原因が結果的に、損失だったり、ユーザーの評価を下げてしまうことになる可能性があります?

今回はテストコードを書く際の大切な原則について書いていきたいと思います!!

①各exampleで期待する値は1つだけ

期待する値を2つ以上含めてしまうと、どちらのエクスペクテーションでエラーが出たのか判別できず、正確なテストができないため、1つだけにしておきましょう!!

※エクスペクテーション(予想、期待、切望、待望)

②期待する結果をはっきりと分かりやすく記述

明快な記述にすることで、自身の確認やメンバーとの共有、顧客への仕様説明が楽になります。
結果としてコミュニケーションミスが低下し、スムーズに仕事を進めることができます。

もし分かりづらい記述だったら、一々相手に確認をしてテストするという無駄な時間が生まれますよね?

③起きて欲しいことと起きてほしくないこと両方をテストする

これはどちらもテストで予期せぬ動作が残るのを防ぐためにどっちも行います!!

そうすればエラー発生率の低下に繋がると思っています?

④境界値をテストする

例えば、パスワード登録の際に8文字以上を保存するとしましょう。
テストする際には、8文字以上保存されているかの確認と、逆に7文字以下のパスワードは保存されていないかテストをする必要があります。
よくバリデーションとかに使われるので、しっかりチェックする必要がありますね?

可読性を考えつつ、適度にDRYする

DRYとはDon't Repeat Yourselfの略になります。
テストコードにおいて何よりも相手に伝わる分かりやすさが大切です。
分かりづらくなってテストの見落としが起きるよりマシだと思いませんか?

最後に

本番環境前には必ずテストコードを書き、
ちゃんとメソッドが定義されているのか、
値がしっかり取得されているのかを確認してしっかりとしたアプリケーションを作っていきましょう!!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails6 のちょい足しな新機能を試す27(perform_deliveries 編)

はじめに

Rails 6 に追加されそうな新機能を試す第27段。 今回は、 perform_deliveries 編です。
perform_deliveries の値が false(nil) のとき、log への出力メッセージがメールの送信をスキップしたことを示す内容に変わりました。

今回は、User を登録するときに perform_deliveries の値を画面から指定できるようにする(メールを送信する、しないを指定できるようにする)ことにより、動作を確認します。

Ruby 2.6.3, Rails 6.0.0.rc1 で確認しました。Rails 6.0.0.rc1 は gem install rails --prerelease でインストールできます。

$  rails --version
Rails 6.0.0.rc1

Rails プロジェクトを作る

$ rails new rails6_0_0rc1
$ cd rails6_0_0rc1

User の CRUD を作る

User の CRUD を作ります。

$ rails g scaffold User name

UserMailer を作る

メールを送信できるように、UserMailer を作ります。

$ rails g mailer UserMailer

View を変更する

_form.html.erbperform_deliveries を true にするか false にするか指定するチェックボックスを追加します。

app/views/users/_form.html.erb
<%= form_with(model: user, local: true) do |form| %>
  ...
  <div class="field">
    <%= label_tag :perform_deliveries %>
    <%= check_box_tag :perform_deliveries %>
  </div>
  ...
<% end %>

User controller を変更する

UsersController#create メソッドを変更し、DBへの保存が成功したら、 メールを送信するようにします。
このとき、perform_deliveries の値をパラメータとして UserMailer に渡すようにします。

app/controllers/users_controller.rb
class UsersController < ApplicationController
  ...
  def create
    @user = User.new(user_params)

    respond_to do |format|
      if @user.save
        perform_deliveries = params[:perform_deliveries].to_i == 1
        UserMailer.with(user: @user, perform_deliveries: perform_deliveries).created_email.deliver_later
        format.html { redirect_to @user, notice: 'User was successfully created.' }
        format.json { render :show, status: :created, location: @user }
      else
        format.html { render :new }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end
  ...
end

以下の2行が追加した部分になります。

        perform_deliveries = params[:perform_deliveries].to_i == 1
        UserMailer.with(user: @user, perform_deliveries: perform_deliveries).created_email.deliver_later

このあとは、 UserMailer 側を修正していきます。

UserMailer クラスにメソッドを追加する

メールを送信する created_email メソッド と perform_deliveries を設定するコールバックを追加します。

app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer
  after_action :set_perform_deliveries

  def created_email
    @user = params[:user]
    mail(to: 'admin@example.com', subject: 'user created')
  end

  private

  def set_perform_deliveries
    mail.perform_deliveries = params[:perform_deliveries]
  end
end

メールのテンプレートを作成する

今回は手抜きで テキストメールのみとし、 HTML メールは作成しません。

app/views/user_mailer/created_email.text.erb
User created
=============

User <%= @user.name %> was created

メールをファイルに保存する

今回は実際にメールを送信せず、ファイルに保存するように設定を変更します。

config/environments/development.rb
Rails.application.configure do
  ...
  config.action_mailer.delivery_method = :file
  ...
end

db:migrate を実行する

$ bin/rails db:create db:migrate

rails server を実行してブラウザからUserを登録する

User を登録するときに、 perform_deliveries チェックボックスをチェックします。
ユーザーが無事、登録できれば、メールは、tmp/mails ディレクトリ内に保存されます。
このときログを確認すると

log/development.log
... Delivered mail 5ce9f3619b8f4_2f32ae97743a3b0258ac@8baf8e28fbad.mail (6.1ms)

とメールが送信されたことが記録されています。

今度は、perform_deliveries チェックボックスをチェックしないで User を登録します。
tmp/mails ディレクトリの admin@example.com ファイルには何も追加されません。
このときログを確認すると Delivered とはならずに

log/development.log
... Skipped delivery of mail 5ce9f380b1ad6_2f32ae97743a3b025957@8baf8e28fbad.mail as `perform_deliveries` is false

とメールの送信をスキップしたことがログに記録されます。 (←これが今回のちょい足し機能です。)

試したソース

試したソースは以下にあります。
https://github.com/suketa/rails6_0_0rc1/tree/try027_perform_deliveries

参考情報

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ReactやVueなどのJavascriptフレームワークからRailsの多対多モデルに対して、関連付けも含めて一気に作ってみた

こんにちは!@hairgaiです。
突然ですが、とあるTeamを作成するときにMemberを一緒に所属させたい!と思うことって一日に一回くらいありませんか?
今回は、それを実装するときにJavascriptからRailsへのパラメータで若干悩んだので、それを共有しようかなと思います。

前提

よくある多対多です。

  • Teamモデル
    • has_many :team_members
    • has_many :members, through: :team_members
  • TeamMemberモデル
    • belongs_to :team
    • belongs_to :member
  • Memberモデル
    • has_many :team_members: :destroy
    • has_many :teams, through: :team_members

React 16.8.6、Rails 5.2.2

実装

Memberが数人いて何かTeamを作るときに、一度作成して後から所属させるのは面倒なので、当然ながら「Teamを作るときにMemberを所属させつつ作れたらいいのに」と思うと思います。
なので、フロントでTeamを作成するときに、既に登録済みのMemberを一覧で表示して、それを選択させることでパラメータを同時に送らせることにします。

image.png

こんな感じですね。

また、Railsでは、モデルを作成するときに、その多対多関係にあるモデルを一緒に関連付けることが可能です。
なので、上記のように「Teamを作るときにMemberを所属させつつ作れたらいいのに」と思ったら、

pry(main)> Member.create!(email: 'a@example.com')

=> #<Member:0x00007fb1498f04d8
  id: 1,
  email: "a@example.com",
  # ...

pry(main)> team = Team.create!(name: 'hoge', member_ids: [1])

=> #<Team:0x00007fb142722860
  id: 1,
  name: "hoge",
  # ...

pry(main)> team.members

=> [#<Member:0x00007fb149951af8
  id: 1,
  email: "a@example.com",
  # ...
  ]

のように、[モデル名]_idsというパラメータに配列を渡すと関連付けることが出来ます。
なので、フロント側でこのパラメータが渡ってくるようにURLパラメータを生成すれば良いということですね。

パラメータ送りたい

ググると色々な記事が出てくる通り、JavascriptからURLにパラメータ用のクエリを乗っけるときは、qsを使いました。
qsは、Javascriptの連想配列(Hash)からURLパラメータを生成してくれるライブラリで、例えば

import qs from 'qs'; // or var qs = require('qs');

const params = { team: { name: 'hoge' }};
qs.stringify(params) // => 'team%5Bname%5D=hoge'

という感じで使います。
なので(今回はパラメータの話なので解説しませんが)、フロント側でいい感じにパラメータを連想配列として生成します。

// 実際はフレームワーク上でユーザの入力に合わせて作りますが、下記のような連想配列が生成されます。
const params = {
  team: {
    name: 'hoge',
    member_ids: [2, 3]
  }
}

qs.stringify(params) // => 'team%5Bname%5D=hoge&team%5Bmember_ids%5D%5B0%5D=2&team%5Bmember_ids%5D%5B1%5D=3'

これをライブラリ等を用いてRailsに送ってみると…(axiosを使いました)

    15: def update
    16:   binding.pry
 => 17:   @team.update!(team_params)
    # ...

[1] pry(#<Api::V1::TeamsController>)> params
=> <ActionController::Parameters {"team"=>{"id"=>"1", "name"=>"hoge", "member_ids"=>{"0"=>"1", "1"=>"2", "2"=>"3"}}, "format"=>"json", "controller"=>"api/v1/teams", "action"=>"update", "id"=>"1"} permitted: false>

あれ?なんか変な形で送られてますね。

クエリの生成方法のオプションがあった

qsが生成したURLパラメータをデコードしてみると…

team[name]=hoge&team[member_ids][0]=2&team[member_ids][1]=3

ということで、team[member_ids][0]=2&team[member_ids][1]=3のように指定されています。これをRailsでは"member_ids"=>{"0"=>"2", "1"=>"3"}と解釈してしまうようですね。(確かにHashっぽいです)
では、Railsではどう記述すればArrayと解釈されるのか、ということで、逆にArrayからクエリを生成してみましょう。

pry(main)> { name: 'hoge', member_ids: [2, 3] }.to_query('team')
=> "team%5Bmember_ids%5D%5B%5D=2&team%5Bmember_ids%5D%5B%5D=3&team%5Bname%5D=hoge"

# => team[member_ids][]=2&team[member_ids][]=3&team[name]=hoge

順番は違いますが、若干指定の仕方が違いますね。Arrayのクエリでは、[]のように数字を入れずに指定すれば良いようです。
現在はその数字の処理はqs側にまかせています。qsのGitHubをよく読んでみると…

You may use the arrayFormat option to specify the format of the output array:

qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })
// 'a[0]=b&a[1]=c'
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })
// 'a[]=b&a[]=c'
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })
// 'a=b&a=c'
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'comma' })
// 'a=b,c'

とのことです。
なので、フロント側でURLパラメータを生成する際に、

const params = {
  team: {
    name: 'hoge',
    member_ids: [2, 3]
  }
}

qs.stringify(params, { arrayFormat: 'brackets' }) // => 'team%5Bname%5D=hoge&team%5Bmember_ids%5D%5B%5D=2&team%5Bmember_ids%5D%5B%5D=3'

とオプションを追加してみると…

[1] pry(#<Api::V1::TeamsController>)> params
=> <ActionController::Parameters {"team"=>{"id"=>"1", "name"=>"hoge", "member_ids"=>["2", "3"]}, "format"=>"json", "controller"=>"api/v1/teams", "action"=>"update", "id"=>"1"} permitted: false>

出来ました!レコードも正常に作られます。

結論

Railsは、Railsが提供するWayに沿えば非常に強力なフレームワークですが、その分色々な決まりがあるので、こういった細かいところもキチンと調べていきたいですね。

この記事が誰かの参考になれば幸いです。

参考

ありがとうございました!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

~勉強会~ヘルスケアwebサービスを自分で作る医者の日記

やっぱ勉強会に参加は有意義
1人でやると煮詰まるし、上級者や他の人の視点で、視界や開ける。

rails チュートリアル4章まで終了
頑張ろう

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む