1

在 Rails 2.2 项目中,我让用户将项目列表放在一个投资组合对象中(即:)PortfolioHasManyProjects。页面上有一个用于常规文本、标题等的 Rails 表单,以及 2 个可排序列表;这些列表用于将项目从全局项目列表拖到您的投资组合项目列表中。

它类似于这里所做的:http: //ui.jquery.com/latest/demos/functional/#ui.sortable

我有投资组合列表 (#drag_list) 更新更改并通过 AJAX 调用提交其​​序列化数据。 这是在 application.js 文件中完成的:

jQuery.ajaxSetup({ 
  'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
})

jQuery.fn.submitDragWithAjax = function() {
  this.submit(function() {
    $.post(this.action, $("#drag_list").sortable('serialize'), null, "script");
    return false;
  })
  return this;
};

$(document).ajaxSend(function(event, request, settings) {
  if (typeof(AUTH_TOKEN) == "undefined") return;
  // settings.data is a serialized string like "foo=bar&baz=boink" (or null)
  settings.data = settings.data || "";
  settings.data += (settings.data ? "&" : "") + "authenticity_token=" + encodeURIComponent(AUTH_TOKEN);
});


/-------------------------------------------/

$(document).ready(function(){

    $(".ajax_drag").submitDragWithAjax();

    $("#drag_list").sortable({
        placeholder: "ui-selected",
        revert: true,
        connectWith:["#add_list"],
        update : function () {
            $("#drag_list").submit();
        }
    });

    $("#add_list").sortable({ 
        placeholder: "ui-selected",
        revert: true,
        connectWith:["#drag_list"]
    });

这就是事情变得棘手的地方。我不确定如何处理序列化数据并将其与表单一起提交给new.html.erb文件中的控制器。所以我所做的就是new.js.erb将隐藏的表单字段new.html.erb与我将在控制器中提取的数据一起插入。

这是 new.js.erb:

$("#projects").html("");
<% r = params[:proj] %>
<% order=1 %>
<% for i in r %>
  $("#projects").append("<input type=hidden name=proj[<%=order%>] value=<%=i%> />");
  <% order=order+1 %>
<% end %>

编辑new.html.erb:

<h1>New portfolio</h1>
<h2>The List</h2>

<div class="list_box">
  <h3>All Available Projects</h3>
  <%= render :partial => "projects/add_list" %>
</div>

<div class="list_box">
  <h3>Projects currently in your new portfolio</h3>
  <%= render :partial => "projects/drag_list" %>
</div>

<div style="clear:both"></div>
<br/>
<br/>

<h2>Portfolio details</h2>
<% form_for(@portfolio) do |f| %>
  <%= f.error_messages %>
  <h3>Portfolio Name</h3>
  <p>
    <%= f.text_field :name %>
  </p>
  <h3>URL</h3>
  <p>
    <%= f.text_field :url %>
  </p>
  <h3>Details</h3>
  <p>
    <%= f.text_area :details %>
  </p>
  <p>

    <div id="projects">
    <input type="hidden" name="proj" value="" />   
    </div>

    <%= f.submit "Create" %>
  </p>
<% end %>

然后表单提交到投资组合控制器中的 create 方法:

  def new
    @projects = Project.find(:all)
    @portfolio = Portfolio.new
    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @portfolio }
      format.js
    end
  end




 def create
    @portfolio = Portfolio.new(params[:portfolio])
    proj_ids = params[:proj]
    @portfolio.projects = []
    @portfolio.save

    proj_ids.each {|key, value| puts "Key:#{key} , Value:#{value} " }
    proj_ids.each_value {|value| @portfolio.projects << Project.find_by_id(value) }

    respond_to do |format|
      if @portfolio.save
        flash[:notice] = 'Portfolio was successfully created.'
        format.html {  render :action => "index" }
        format.xml  { render :xml => @portfolio, :status => :created, :location => @portfolio }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @portfolio.errors, :status => :unprocessable_entity }
      end
    end
  end

所以最后我的问题:

  1. 这是这样做的正确方法吗?出于某种原因,我觉得不是,主要是因为在 Rails 中做其他所有事情似乎都更容易和直观。这行得通,但要做到这一点是地狱。必须有一种更优雅的方式通过 AJAX 调用向控制器发送序列化数据。

  2. 我将如何在同一页面上调用不同的 AJAX 操作?假设我有一个可排序和一个自动完成的 AJAX 调用,我可以有一个sortable.js.erbautocomplete.js.erb从任何文件中调用它们吗?我不确定如何设置控制器来对此做出响应。

4

2 回答 2

2

如果您使用 jQuery,这是一个很好的解决方案。

从链接的博客:

我刚刚为 Rails/jQuery 应用程序编写了一些可排序的代码,并想我会写下它需要多少代码,以及我在后端使用的单个 MySQL 查询。

于 2009-01-08T11:34:27.323 回答
0

这是我基于 Silviu 提到的文章的解决方案。我正在对属于课程的部分进行排序,因此包含了课程 ID。

这是在视图中 - 我正在使用 HAML,因此您必须转换为 erb。

#sorter
- @lesson.parts.each do |part|
  %div[part] <- HAML rocks - this constructs a div <div id="the_part_id" class="part">
    = part_screenshot part, :tiny
    = part.swf_asset.filename

js看起来像这样:

    $('#sorter').sortable({items:'.part', containment:'parent', axis:'y', update: function() {
  $.post('/admin/lessons/' + LessonId + '/parts/sort', '_method=post&authenticity_token='+ AUTH_TOKEN+'&'+$(this).sortable('serialize'));
  $('#sorter').effect("highlight");
}});

这是 PartsController 中调用的方法:

def sort
load_lesson
part_positions = params[:part].to_a
@parts.each_with_index do |part, i|
  part.position = part_positions.index(part.id.to_s) + 1
  part.save
end
render :text => 'ok'

结尾

def load_lesson
@lesson = Lesson.find(params[:lesson_id])
@parts = @lesson.parts

结尾

它需要一些工作来向用户提供反馈,但这对我有用。

于 2009-01-21T02:24:16.613 回答