2009-01-04 4 views
1

Dans un projet Rails 2.2, les utilisateurs créent une liste de projets dans un objet de portefeuille (par exemple: PortfolioHasManyProjects). Sur la page est un formulaire Rails pour le texte régulier, les titres, etc., ainsi que 2 listes triables; Les listes sont utilisées pour faire glisser des projets de la liste globale de projets dans votre liste de projets.RubyOnRails 2.2 + Jquery UI Sortable & AJAX: Voici comment je l'ai fait. Y a-t-il un meilleur moyen?

Il est similaire à ce qui est fait ici: http://ui.jquery.com/latest/demos/functional/#ui.sortable.

J'ai la liste de portefeuille (#drag_list) mise à jour à la modification et la soumission de ses données sérialisées via un appel AJAX. Cela se fait dans le fichier 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"] 
    }); 

Voici où les choses se sont difficiles. Je ne savais pas comment traiter les données sérialisées et je l'ai soumis avec le formulaire au contrôleur dans le fichier new.html.erb. Donc ce que j'ai fait était d'avoir les champs de formulaire cachés new.js.erb dans new.html.erb avec les données que je voudrais extraire dans le contrôleur.

est ici le 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 %> 

qui édite 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 %> 

La forme soumet ensuite la méthode créer dans le contrôleur de portefeuille :

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 

Alors enfin ma question:

  1. Est-ce une bonne façon de le faire? Pour une raison quelconque, je pense que ce n'est pas le cas, surtout parce que tout le reste dans Rails semblait tellement plus facile et intuitif. Cela fonctionne, mais c'était l'enfer pour l'obtenir. Il doit y avoir une manière plus élégante d'envoyer des données sérialisées au contrôleur via des appels AJAX.

  2. Comment appeler différentes actions AJAX sur la même page? Disons que j'ai eu un triable et un appel AJAX autocomplete, pourrais-je avoir un sortable.js.erb et autocomplete.js.erb et les appeler à partir de n'importe quel fichier? Je ne sais pas comment configurer les contrôleurs pour répondre à cela.

+0

Voici ma prise sur ceci: http://awesomeful.net/posts/47-sortable-lists-with-jquery-in-rails – hgmnz

+0

Je ne comprends pas la question (et malheureusement, il y a une limite stupide rep commentant, donc je posterai ceci comme réponse). Pourquoi insérez-vous les champs cachés? Ne pouvez-vous pas simplement utiliser des ID sur les éléments <li> puis appelez 'toArray' sur le sortable plutôt que sur 'sérialiser')? Vous pouvez ajouter cette information à un seul champ de formulaire caché avant que le formulaire ne le soumette. Cela empêcherait tous les appels Ajax après la mise à jour de la liste des projets. – eelco

Répondre

2

Ceci est un nice solution si vous utilisez jQuery.

Depuis le blog lié:

Je viens d'écrire un code sortable pour une application Rails/jQuery et pensé que je le blog à quel point peu de code qu'il faut, et aussi la requête MySQL simple je sur le back-end .

0

Voici ma solution qui est basée sur l'article mentionné par Silviu. Je suis en train de trier les parties qui appartiennent à des leçons, d'où l'inclusion du lessonID.

Ceci est dans la vue - J'utilise HAML donc vous devrez convertir en 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 

Les js ressemble à ceci:

$('#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"); 
}}); 

et voici la méthode qui est appelée dans le 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' 

fin

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

fin

Il faut un peu de travail pour donner des commentaires à l'utilisateur, mais fait le tour pour moi.

Questions connexes