2

Railsコントローラーの例を見ると、通常、次のようなものが表示されます。

class WidgetController < ActionController::Base

  def new
    @widget = Widget.new
  end

  def create
    @widget = Widget.new(params[:id])
    if @widget.save
      redirect_to @widget
    else
      render 'new'
    end
  end
end

これは機能しますが、いくつかの問題があります。

ルート

ウィジェットをroutes.rbファイルに追加した場合:

Example::Application.routes.draw do
  resources :widgets
end

GET /widgets/newにルーティングされnewPOST /widgetsにルーティングされcreateます。

ユーザーが新しいウィジェットページに誤った情報を入力して送信すると、ブラウザに。が付いたURLが表示/widgetsされますが、新しいテンプレートはレンダリングされます。ユーザーがページをブックマークして後で戻るか、ページを更新すると、新しいアクションの代わりにインデックスアクションが呼び出されますが、これはユーザーが期待するものではありません。インデックスアクションがない場合、またはユーザーにインデックスアクションを表示する権限がない場合、応答は404になります。

コードの複製

不自然な例として、新しいメソッドにトリッキーなロジックがあったとしましょう。

def new
  @widget = Widget.new
  do_something_tricky()
end

new現在のアプローチを使用して、そのロジックをとに複製しcreateます。newから呼び出すこともできますが、定義されているかどうかを確認createするために変更する必要があります。new@widget

def new
  @widget ||= Widget.new
  do_something_tricky()
end

さらに、これはコントローラーのアクションの直交性を低下させるため、間違っていると感じます。

何をすべきか?

では、この問題を解決するRailsの方法は何でしょうか。new新しいテンプレートをレンダリングする代わりににリダイレクトする必要がありますか?new中に電話する必要がありcreateますか?私はそれと一緒に暮らすべきですか?もっと良い方法はありますか?

4

5 に答える 5

1

do_something_tricky()独自のメソッドを挿入し、それをcreateアクション内で呼び出します(ただし、新しいテンプレートをレンダリングする場合、つまり検証が失敗した場合のみ)。

ブックマークの問題については、それを防ぐ良い方法はわかりませんが、ルートを変更し、作成アクションを新しいアクションに設定しますが、POST

get '/users/new' => 'users#new'
post '/users/new' => 'users#create'

更新:使用resources

resources :platos, except: :create do
  post '/new' => 'plates#create', on: :collection, as: :create
end

create_platos_pathその後、フォームで使用できます

于 2013-03-04T01:24:20.413 に答える
1

一般に、問題を解決するRailsの方法は、トリッキーなメソッドをモデルに配置するか、ヘルパーメソッドとして使用することであると思います。そのため、コントローラーは「シン」のままであり、両方にカスタム動作を追加する必要はありません。#newおよび#create

編集:さらに読むために、「Rails AntiPatterns」の本をお勧めします。これらの一般的な設計上の問題の多くを経験し、潜在的な解決策を提供するからです。

于 2013-03-04T01:29:10.880 に答える
1

これは「レールウェイ」の問題ではないと思いますし、手を汚さずにこれを可能にする組み込み機能はありません。送信したばかりでエラーが発生したフォームをブックマークする場合、ユーザーは何を期待しますか?ユーザーはよくわからないので、失敗したフォームをブックマークしないでください。

new_widget_pathにリダイレクトするのが最もクリーンなソリューションだと思います。ただし、エラーを保持してフォームに表示する必要があります。このために、パラメータをセッション内に保持することをお勧めします(シリアル化されたウィジェットオブジェクトよりも小さいと予想されます)。

def new
  @widget = widget_from_session || Widget.new 
end

def widget_from_session
  Widget.new(session.delete(:widget_params)) if session[:widget_params].present?
end
private :widget_from_session

# Before the redirect
session[:widget_params] =  params

コードは自明であり、nilを返すWidget.new場合にのみ呼び出されwidget_from_sessionます。これは、session [:widget_params]が存在する場合です。ハッシュを呼び出すdeleteと、削除された値が返され、元のハッシュから削除されます。

UPDATEオプション2ajaxを使用してフォームを送信するのはどうですか?コントローラは次のメリットを享受できます。

  respond_to :html, :json

  ...

  def create
    @widget = Widget.new params[:widget]
    @widget
    respond_with @widget, location: nil
  end

応答コード(Rails:201Createdまたは422Unprocessable Entityによって設定されます)に基づいて、エラー(検証が失敗したときに応答の本文で利用可能)を表示したり、ユーザーを@widgetにリダイレクトしたりできます。

これはStackOverflowがそれを行う方法です:https ://stackoverflow.com/questions/ask 。フォームを非同期で送信します。

于 2013-03-12T02:38:13.553 に答える
0

2つのアクションで同じ関数を記述する必要はありません。代わりにbefore_filterを使用してください。

間違った送信後に「widget_new_url」が必要な場合は、フォームに:url=>widget_new_pathのような新しいウィジェットパスのURLを追加します。

RailsはFormからURLを取得します。

于 2013-03-08T14:35:58.640 に答える
0

以前にこの問題が発生したため、代わりに編集アクションを使用します。

これが私のコードです。

ルート:

resources :wines do
  collection do
    get :create_wine, as: :create_wine
  end
end

コントローラ:

def create_wine
  @wine = Wine.find_uncomplete_or_create_without_validation(current_user)
  redirect_to edit_wine_path(@wine)
end

def edit
  @wine = Wine.find(params[:id])
end

def update
  @wine = Wine.find(params[:id])
  if @wine.update_attributes(params[:wine])
    redirect_to @wine, notice: "#{@wine.name} updated"
  else
    render :edit
  end
end

モデル:

def self.find_uncomplete_or_create_without_validation(user)
  wine = user.wines.uncomplete.first || self.create_without_validation(user)
end

def self.create_without_validation(user)
  wine = user.wines.build
  wine.save(validate: false)
  wine
end

意見:

= simple_form_for @wine, html: { class: 'form-horizontal' } do |f|
  = f.input :complete, as: :hidden, input_html: { value: 'true' }

私がしたことは、getactionを使用して新しいアクション'create_wine'を作成することです。

  1. ユーザーが「create_wine」をリクエストすると、検証なしで新しいワインが作成され、属性の更新フォームとcompeleの非表示フィールドを使用してアクションを編集するようにリダイレクトされます。
  2. ユーザーが以前に作成したことがあるが、ワインの保存をあきらめた場合、最後の未完成のワインが返されます。

つまり、保存するかどうかに関係なく、URLは/ wines /:idと同じになります。

RESTfulな設計にはあまり適していませんが、私の問題は解決します。より良い解決策があれば私に知らせてください。

于 2013-03-11T07:38:36.783 に答える