【问题标题】::remote => true confusion with form_for:remote => 与 form_for 真正混淆
【发布时间】:2012-09-16 03:22:12
【问题描述】:

我只是在学习 Rails,如果有任何帮助,我将不胜感激。我在form_for 上查看了:remote => true 的大概10 个教程,它们似乎都相互复制(同样令人困惑)。

本教程就是其中之一:http://tech.thereq.com/post/18910961502/rails-3-using-form-remote-true-with-jquery-ujs

我的网络应用程序几乎都在一个页面上,我的“提交表单”在一个弹出式灯箱内。这意味着 form_for 代码实际上在我的 index.html.erb 中。这也意味着为index 创建了一个新的@playlist 实例变量(而不是在new 中)

我的最终目标是这样的:

if @playlist.save 返回true,我想通过:通知将用户重定向到root_path。无需使用成功消息或类似内容更新表单。我想在保存成功时进行硬重定向。

if @playlist.save 返回false,我想渲染 create.js.erb 中的代码,这会将错误附加到灯箱表单中而不刷新页面。 注意 很多教程似乎都想将整个表单重新渲染为 html,然后将内容替换到位。我宁愿(如果可以的话)将错误发送到表单并插入它们,我认为重新渲染和替换整个表单似乎比它必须的更复杂。

截至目前,我的代码有点混乱,尤其是:

  • respond_to 块。这是对这里实际情况的最大困惑,我尝试了很多不同的代码,但没有任何效果
  • 我不知道 create.js.erb 是否正确
  • 我没有 create.html.erb - 我认为这是正确的,因为我只想重定向

表单的第一行:

<%= form_for @playlist, :remote => true do |f| %>

我的整个播放列表控制器

class PlaylistsController < ApplicationController

  before_filter :load_genres, :only =>[:index, :user]
  before_filter :new_playlist, :only => [:index, :new, :create]

  def index
    @playlists = Playlist.order('created_at DESC').page(params[:page]).per(30)
  end

  def new
  end

  def create
    respond_to do |format|
      if @playlist.save
        # ???
        format.html { redirect_to root_path, :notice => "Playlist submitted" }
      else
        # ???
        format.js { render :js => @playlist.errors, :status => :unprocessable_entity }
      end
    end
  end

  def user
    @playlists = Playlist.order('created_at DESC').where(:username => params[:username]).page(params[:page]).per(30)
  end

  def listen
    playlist = Playlist.find(params[:playlist_id])
    playlist.update_attribute(:listens, playlist.listens + 1)
    render :nothing => true
  end

  private

  def load_genres
    @genres = Genre.order(:name)
  end

  def new_playlist
    @playlist = Playlist.new(:title => params[:title], :url => params[:url], :description => params[:description])
  end

end

create.js.erb

jQuery(function($) {
    alert('createjs called');
    $('#submit-form form').on('ajax:error', function(event, xhr, status, error){

        var responseObject = $.parseJSON(xhr.responseText), 
            errors = $('<ul />');

        $.each(responseObject, function(index, value){
            errors.append('<li>' + value + '</li>');
        })

        $(this).find('.submit-playlist-errors').html(errors);
    });
});

【问题讨论】:

  • 我实际上对您正在努力解决的问题以及您需要实现的目标感到有些困惑。什么有效,什么无效。您能否简化并分解您的问题?
  • 相信我,我曾尝试在其他论坛等上对其进行分解。这很难解释,我试图让它非常清楚我在寻找什么。截至目前,它只是不起作用,期间。我知道问题出在我的 respond_to 块上,主要是因为我不理解它,而且我读过的所有教程都对这个主题感到困惑
  • 我意识到一个错误是我有这个:@playlist = Playlist.new(:title =&gt; params[:title], :url =&gt; params[:url], :description =&gt; params[:description])。它应该只是params[:playlist]。我会马上给出我遇到的确切错误

标签: jquery ruby-on-rails ruby ajax ruby-on-rails-3


【解决方案1】:

如果我对您的理解正确,您有一个表单,并且您想使用flash 进行重定向,请注意表单是否已保存。如果表单无效,您希望显示错误。

您可以将表单(或任何请求)以不同的格式(通常是 html、json 和 js)发送到 rails 应用程序。这在您提供的网址中指定。

playlist_path(@playlist)
# => /playlists/1

playlist_path(@playlist, :format => "json")
# => /playlists/1.json

playlist_path(@playlist, :format => "html")
# => /playlists/1.html
# ... etc

格式告诉 Rails 要使用您的 respond_to 块中指定的响应类型。

现在,如果这很清楚,您必须决定使用哪种格式。

如果您指定js 格式,响应将被视为script 执行。如果表单有效,您可以发送用户 javascript,将他们重定向到您想要的页面。如果表单无效,您可以通过修改 HTML 的方式来显示错误消息。无需客户端代码。

respond_to do |format|
  if valid
    format.js { render "valid" }
  else
    format.js { render "invalid", :status => :unprocessable_entity }
  end
end

# valid.js.erb
window.location = <%= your_path %>

# invalid.js.erb
// whatever to display errors

当您使用json 时,如果表单无效,您可以返回重定向 url 以重定向用户或错误。请注意,此解决方案需要客户端的 Javascript 来处理它。

# controller
respond_to do |format|
  if valid
    format.json { render :json => your_path }
  else
    format.json { render :json => @object.errors, :status => :unprocessable_entity }
  end
end

# client side javascript
$("form")
  .on("ajax:success", function(event, data, status, response) {
    window.location = data
  })
  .on("ajax:error", function(event, response, error) {
    // logic to handle errors
  })

您也可以使用html 格式(通过将格式设置为html 或根本不指定格式)。但是,如果您使用:remote =&gt; true,则必须以与json 相同的方式对待它(具有客户端javascript)。如果您使用redirect_to 作为响应,它将重定向请求,而不是您的用户。

我不确定在用户被重定向后是否显示 flash 消息,但您可以这样尝试:

respond_to do |format|
  if valid
    format.html { 
      flash[:notice] = "Playlist submitted"
      render :json => your_path }
  else
    format.html { render :json => @object.errors, :status => :unprocessable_entity }
  end
end

# client side javascript
//...

希望这会使您的respond_to 块变干。

【讨论】:

  • 有没有一种方法可以在不使用 javascript 的情况下进行重定向?就像服务器发回的响应重定向它们一样?
  • 恐怕没有这种办法。您可以通过调用 render :js =&gt; "window.location = #{your_path}" 来简化使用控制器中的 JavaScript 进行重定向。
  • 我不断收到这个错误:!!处理请求时出现意外错误::playlist_hash:Symbol 的未定义方法“bytesize”!处理请求时出现意外错误:死锁;递归锁定
  • 第一个错误似乎是 params 的问题,后来的错误似乎是数据库的问题。但这只是猜测。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-07
  • 1970-01-01
  • 2014-07-09
  • 1970-01-01
  • 2016-01-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多