New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP]Model と画面上の form が1対1で一致しない場合、どのように実装するのが綺麗なのか? #2

Open
willnet opened this Issue Feb 3, 2018 · 1 comment

Comments

Projects
None yet
1 participant
@willnet
Contributor

willnet commented Feb 3, 2018

Railsのきれいなコードのお題案 · Issue #1 · clean-rails-ja/conversationからの転載

Model と画面上の form が1対1で一致しない場合、どのように実装するのが綺麗なのか?

ブログにカテゴリーを複数つけて投稿する機能。
はてなブログの投稿画面がイメージに近いです。

blog_img

おそらく、モデルは下記のように複数のモデルになると思います。

# app/models/article.rb
class Article < ApplicationRecord
  has_many :categories
end

# app/models/category.rb
class Category < ApplicationRecord
  belongs_to :article
end

実装方法の例

下記のような方法があると思いますが、それぞれメリット・デメリットがあると思う。

私が知らないだけで、他にも良い実装方法はあるかも。

@willnet

This comment has been minimized.

Contributor

willnet commented Feb 3, 2018

この例、厳密に考えるとArticleとCategoryは多対多な気がするけど、面倒なのでいったん1対多で考えますね。

accepts_nested_attributes_for の例

class Article < ApplicationRecord
  has_many :categories
  accepts_nested_attributes_for :categories, allow_destroy: true, reject_if: :all_blank
end

class Category < ApplicationRecord
  belongs_to :article
end

class ArticlesController < ApplicationController
  # ...
  def create
    # ...
  end

  def update
    @article = Article.find(params[:id])
    if @article.update(article_params)
      redirect_to article_path(@article), notice: '更新しました'
    else
      render :edit      
    end
  end

  def article_params
    params.require(:article).permit(:title, :body, categories_attributes: [:id, :name, :_destroy])
  end
end
<%= form_with @article do |f| %>
    <%= f.text_field :title %>
    <%= f.text_area :body %>
    <%= f.field_for :categories |g| %>
      <%= g.text_field :name %>
      削除する <%= g.check_box :_destroy %>
    <% end %>
  <% f.submit %>
<% end %>

メリット

  • 全部自分で書くのと比べてコード量が格段に減る

デメリット

  • 覚えづらい、ハマりやすいインターフェース
    • reject_if_destroy
    • accepts_nested_attributes_forを定義するとfields_forの挙動が変わる
      • name属性がnested attributes仕様に変わる
  • モデルの定義とビューの定義が一体化される
  • レールから外れたいときに大変
    • 保存時にbelongs_toのバリデーションが走ってN+1になってしまう、みたいなケースがあった気がする
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment