Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails rubyonrails控制器设计_Ruby On Rails - Fatal编程技术网

Ruby on rails rubyonrails控制器设计

Ruby on rails rubyonrails控制器设计,ruby-on-rails,Ruby On Rails,当我查看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'

当我查看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
GET/widgets/new
将路由到
new
POST/widgets
将路由到
create

如果用户在新窗口小部件页面上输入错误信息并提交,他们的浏览器将显示带有
/widgets
的URL,但新模板将被呈现。如果用户为页面添加书签并稍后返回或刷新页面,则将调用索引操作而不是新操作,这不是用户所期望的。如果没有索引操作,或者用户没有查看它的权限,那么响应将是404

代码重复 作为一个人为的例子,假设我的新方法中有一些棘手的逻辑:

def new
  @widget = Widget.new
  do_something_tricky()
end
使用当前的方法,我将在
new
create
中复制该逻辑。我可以从
create
调用
new
,但随后我必须修改
new
以检查
@widget
是否已定义:

def new
  @widget ||= Widget.new
  do_something_tricky()
end
此外,这感觉是错误的,因为它减少了控制器动作的正交性

怎么办?
那么Rails解决这个问题的方法是什么呢?我是否应该重定向到
new
,而不是呈现新模板?我应该在
create
的内部调用
new
?我应该接受它吗?有更好的方法吗?

do\u thicky()
放在它自己的方法中,并在创建操作中调用它(但只有在呈现新模板时,即验证失败时)

至于书签问题,我不知道有什么好方法可以防止它,但是可以修改路由并将创建操作设置为新操作,但是使用
POST

get '/users/new' => 'users#new'
post '/users/new' => 'users#create'
更新:使用
资源

resources :platos, except: :create do
  post '/new' => 'plates#create', on: :collection, as: :create
end
然后您可以在表单中使用
create_platos_path
一般来说,我认为解决问题的Rails方法是将棘手的方法放在模型上或作为辅助方法,这样控制器保持“精简”,并且您不必确保将自定义行为添加到
\new
\create


编辑:为了进一步阅读,我推荐《Rails反模式》这本书,因为它们讨论了许多常见的设计问题并给出了潜在的解决方案。

您不需要在两个动作中编写相同的函数,而是使用before\u filter

如果你想在提交错误后得到“widget\u new\u url”,那么在你的表单中添加新widget路径的url,比如:url=>widget\u new\u path


Rails从表单中获取url。

我以前遇到过这个问题,所以我改用编辑操作

这是我的密码

路线:

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
视图:

我所做的是用get action创建一个新动作“create_wine”

  • 如果用户请求“create_wine”,它将在没有验证的情况下创建一个新的wine,并重定向到编辑操作,其中属性的更新表单和强制的隐藏字段
  • 如果用户以前创建过,但放弃保存葡萄酒,它将返回最后一个未完成的葡萄酒
  • 这意味着无论是否使用save,url都将与/wines/:id相同


    不是很适合RESTful设计,但解决了我的问题。如果有更好的解决方案,请告诉我。

    我认为这在“rails方式”中不是一个问题,并且没有内置的功能可以在不弄脏手的情况下实现这一点。当用户为刚提交但有错误的表单添加书签时,他们期望得到什么?用户并不清楚,他们不应该将失败的表单添加到书签中

    我认为重定向到
    new\u widget\u path
    是最干净的解决方案。但是,您应该保留错误并将其显示在表单上。为此,我建议您将参数保持在会话中(我希望它比序列化的小部件对象小)

    代码是自解释的,
    Widget。只有当来自会话的
    Widget\u返回nil时,才会调用new
    ,此时会话[:Widget\u params]存在。对散列调用
    delete
    ,将返回已删除的值,并将其从原始散列中删除

    更新选项2 使用ajax提交表单怎么样?您的控制器可以受益于:

      respond_to :html, :json
    
      ...
    
      def create
        @widget = Widget.new params[:widget]
        @widget
        respond_with @widget, location: nil
      end
    
    根据响应代码(由Rails:201 Created或422 Unprocessable Entity设置),您可以显示错误(验证失败时在响应主体中可用)或将用户重定向到@widget


    StackOverflow就是这样做的:。他们异步提交表单。

    我意识到我可以编写自己的路由,但我不想。不为资源使用资源路由感觉是错误的。我希望有一种烘焙溶液。我不知道有哪种烘焙溶液能满足你的需要。如果你想在routes中使用
    资源
    ,你可以试试我更新的答案。do_something__技巧的要点是说明代码是如何违反DRY原则的。假设你必须在帖子创建之前和之后做一些事情。我指的是一个丑陋的例子,并不是试图解决一个特定的问题。另外,使用
    /new
    路由调用
    create
    方法仍然感觉不对。Rails反模式看起来是一个不错的读物。谢谢你指出这一点。有没有关于如何避免路由问题的想法?我认为这实际上不是一个问题——我不担心人们能够将他们发布无效数据的页面添加到书签中。如果它是多页向导类型的流的一部分,那么这可能是一个特殊的用例,可能需要重定向到URL中包含状态信息的中间页。在这种情况下,因为它已经重定向到一个成功创建的对象的
    show
    操作,所以他们可以很容易地为它添加书签。我没有考虑在会话中存储对象。我想知道是否有一种方法可以更普遍地做到这一点。尽管如此,我认为这是一种危险的态度
    = simple_form_for @wine, html: { class: 'form-horizontal' } do |f|
      = f.input :complete, as: :hidden, input_html: { value: 'true' }
    
    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
    
      respond_to :html, :json
    
      ...
    
      def create
        @widget = Widget.new params[:widget]
        @widget
        respond_with @widget, location: nil
      end