Je suis nouveau sur les rails et j'ai cette application Web qui permet aux utilisateurs de créer de nouveaux travaux d'impression à l'aide de Rails 4

App / models / job.erb

class Job < ActiveRecord::Base
  belongs_to :job_type
end

App / models / job_type.erb

class Job < ActiveRecord::Base
  has_many :jobs
end

Dans le nouveau formulaire de création d'emploi, l'utilisateur doit choisir un type de travail pour son nouveau travail dans une liste, que j'ai réussi à obtenir en jetant le code suivant.

App / vues / emplois / _form.html.erb

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_for(@job) do |f| %>

      .....

      <div class="field">
        <%= f.label :job_type_id %><br>
        <%= f.collection_select :job_type_id, JobType.all,:id,:name %>
      </div>
      <!-- Modal -->
      <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
        <div class="modal-dialog" role="document">
          <div class="modal-content">
            <div class="modal-header">
              <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
              <h4 class="modal-title" id="myModalLabel">Modal title</h4>
            </div>
            <div class="modal-body">
              ...
            </div>
            <div class="modal-footer">

            </div>
          </div>
        </div>
      </div>

    <% end %>

  </div>
</div>

Et grâce à un script de café, j'ai réussi à ajouter l'option "Autre" au menu Types de travaux, qui déclenche le modal #myModal pour ajouter un nouveau JobType à la base de données s'il n'existe pas ...

App / assets / javascript / jobs.coffee

$('#job_job_type_id').append("<option>Other</option>")
$('#job_job_type_id').change ->
  jobType = $('#job_job_type_id :selected').text()
  if jobType == "Other"
    $('#myModal').modal('show')
  else
    $('#myModal').modal('hide')

Le code fonctionne bien et déclenche le modal bootstrap. Mais c'est tout, je ne sais pas quoi faire ensuite?

J'ai essayé beaucoup de code et passé en revue beaucoup de questions, mais je n'ai pas réussi à rendre ce modal capable d'ajouter un nouveau JobType et de mettre à jour la liste, j'ai pensé qu'il fallait modifier les contrôleurs et le code AJAX de fantaisie au-delà de mes connaissances ...

J'ai quelques questions ici

1) Que dois-je mettre dans le code modal pour pouvoir ajouter un nouveau JobType à la base de données, puis revenir au nouveau formulaire de création de Job et au JobType nouvellement créé sélectionné

2) Quels contrôleurs doivent être modifiés? et comment? De quoi a besoin le code AJAX?

3) Comment re-factoriser le Job_form? Puis-je mettre le code modal dans un nouveau partiel? Si oui, comment mettre en œuvre cela?

J'espère que vous pourrez m'aider, j'ai du mal à résoudre ce problème pendant des jours. Je vous remercie

0
Moataz Zaitoun 8 mars 2016 à 04:26

3 réponses

Meilleure réponse

D'accord, d'abord, pour répondre à vos questions:

1) Que dois-je mettre dans le code modal pour pouvoir ajouter un nouveau JobType à la base de données, puis revenir au nouveau formulaire de création de Job et au JobType nouvellement créé sélectionné

Votre modal ajoutera un formulaire, essentiellement le formulaire que vous avez probablement sous app/views/job_types/_form.html.erb, mais il aura un bouton qui sera soumis via AJAX au lieu de soumettre le formulaire.

2) Quels contrôleurs doivent être modifiés? et comment? De quoi a besoin le code AJAX?

Vous devrez ajouter une méthode à job_types_controller qui peut gérer l'appel AJAX susmentionné. Il devra:

  • Enregistrez le nouveau type de travail
  • Renvoie un statut de réussite et l'entité nouvellement créée à l'appelant.

3) Comment re-factoriser le Job_form? Puis-je mettre le code modal dans un nouveau partiel? Si oui, comment mettre en œuvre cela?

Vous devez disposer d'une méthode qui, lorsqu'elle est appelée, ajoute une nouvelle option à la zone de liste. Vous pouvez mettre le code modal dans une partie ou non, à vous; cette décision n'a aucune conséquence en ce qui concerne la fonctionnalité de tout cela.

Alors, que devez-vous faire ici:

SERVEUR (CONTRÔLEUR):

1) Créez une méthode dans config/routes.rb qui peut gérer un appel AJAX.

resources :job_types do
  post :append, on: :collection
end

Cela ajoute un itinéraire de ressources personnalisé. Parce que nous l'ajoutons de cette façon, nous obtenons automatiquement la fonction URLHelper append_job_types_path.

2) Implémentez cette méthode dans controllers/job_types_controller.rb pour enregistrer un nouveau JobType et le renvoyer (et, plus important encore, son ID) à l'appelant.

def append
  job_type = JobType.new
  job_type.name = params[:job_type_name]
  if job_type.save
    render :status => 201, :json => { id: job_type.id, name: job_type.name }
  else
    err_msg = job_type.errors.empty?? 'Save failed' : job_type.errors.full_messages.join('; ')
    render :status => 400, :json => { message: err_msg }
  end
end

Si la sauvegarde se passe bien, l'ID et le nom de la nouvelle entité seront retournés sous forme de JSON à l'appelant. Sinon, nous renvoyons une erreur et tout message de validation.

Maintenant, nous sommes prêts à utiliser ces méthodes ...

CLIENT (VUE):

1) Créez un bouton qui peut lancer le modal

Vous l'avez déjà fait!

2) Ajouter un formulaire au modal qui peut soumettre un type d'emploi

<%= form_tag(append_job_types_path) do %>
  Enter Job Name:<br/>
  <input type="text" name="new_job_type_name" id="new_job_type_name" />
  <br/>
  <input type="button" value="Submit" id="append_job_type_submit" />
<% end %>

Et vraiment, il n'a pas besoin d'être sous une forme puisque nous soumettons via AJAX, mais vous obtiendrez probablement une aide de style en utilisant un. Cependant, les attributs id ici sont importants pour les étapes suivantes. Notez que j'utilise form_tag ici au lieu de form_for. C'est parce que je ne joindrai rien au formulaire (ni ne le soumettrai d'ailleurs).

3) Lors de la soumission (euh, en cliquant sur le bouton), envoyez le nom entré par l'utilisateur à la nouvelle méthode AJAX

Ici, nous allons utiliser du javascript discret pour accrocher une méthode d'écoute au bouton d'envoi. Vous pouvez mettre ce code en bas de la vue, ou vous pouvez le déplacer vers coffeescript:

javascript:
  $("#append_job_type_submit").click(function() {
    var name = $("#new_job_type_name").val();
    //TODO: validation on the name, ensure it's not blank, etc
    $.ajax({
      url: '/job_types/append',
      method: 'POST',
      data: {job_type_name: name},
      success: function(data) {
        //TODO: Handle success
      },
      error: function(err) {
        //TODO: Handle error
      }
    });
  });

Ici, nous envoyons un appel AJAX à la méthode serveur, en passant le nom entré par l'utilisateur. Notez que j'ai laissé de l'espace pour une validation simple que vous pouvez faire avant la soumission

4) Lors de la réponse, ajoutez la nouvelle option à la zone de liste.

Cela continue la fonction d'en haut:

javascript:
  $("#append_job_type_submit").click(function() {
    var name = $("#new_job_type_name").val();
    //TODO: validation on the name, ensure it's not blank, etc
    $.ajax({
      url: '/job_types/append',
      method: 'POST',
      data: {job_type_name: name},
      success: function(data) {
        var sel = $("#job_type_id");
        sel.append('<option value="' + data.id + '">' + data.name + '</option>');
        $("#myModal").modal('hide');
        alert("New job type " + data.name + " created.");
        //TODO: probably be nice to auto-select this option; I'll leave that exercise to the alert reader
      },
      error: function(err) {
        alert(err.responseJSON.message);
      }
    });
  });

Maintenant, l'utilisateur peut choisir l'option dans la zone de sélection et la nouvelle option a été enregistrée dans la base de données (indépendamment de la création ou non du nouveau travail).

Clause de non-responsabilité : je n'ai pas testé ce code, ni même vérifié s'il se compile. Mais cela devrait fonctionner, et peu importe, c'est le modèle que vous souhaitez suivre, donc si rien d'autre, au moins vous avez la direction maintenant.

Maintenant, tout cela dit, je recommanderais toujours l'autre approche sans AJAX que j'ai suggérée, car elle supprime la plupart de ces étapes, mais c'est juste moi. N'hésitez pas à accepter la réponse qui VOUS aidera à accomplir VOTRE tâche de la façon que VOUS voulez.

Remarque: j'ai décidé de poster ceci en plus de la réponse d'Aldrien car la mienne a quelques différences que j'ai trouvées suffisamment importantes pour le justifier:

  • Une réponse de réussite et d'échec doit renvoyer le code d'état de réussite / échec. Le faire toujours retourner le succès est un peu trompeur. Je pense que les codes d'état sont une partie importante de toute conception REST, même quelque chose d'aussi petit que cela.
  • Je ne recommanderais d'utiliser les match itinéraires qu'en dernier recours. Les itinéraires ingénieux sont plus propres et plus clairs, et ils vous en donnent également plus. De plus, j'aime l'itinéraire sous /job_types et pas seulement flottant à la racine.
  • De plus, une norme devrait être une demande POST au lieu d'un GET; nous créons une nouvelle entité après tout.
  • Bogue: la méthode append devrait donner data.id pour la valeur de l'option, pas data.title (qui devrait être data.name selon le code d'origine). Sinon, la valeur ne sera pas l'ID et la tentative de sauvegarde échouera.
0
GoGoCarl 10 mars 2016 à 16:29

Si je peux proposer une alternative ...

Votre approche va nécessiter des méthodes de codage avancées et, si vous n'êtes pas à l'aise avec AJAX, cela peut être une route difficile.

Comme alternative, je suggère qu'au lieu d'afficher un modal, il suffit d'afficher / masquer une zone de texte dans le formulaire existant pour abriter l'autre nom:

<input type="text" name="other_job_type" />

Ensuite, lorsque vous soumettez le formulaire, comme vous le savez, il ira à JobController # create (ou #update pour les travaux existants). Là, vous pouvez obtenir ce champ:

def create
  save_successful = false
  @job = Job.new params[:job]
  other_job_type = params[:other_job_type]
  if other_job_type
    new_job_type = JobType.new
    new_job_type.name = other_job_type
    save_successful = new_job_type.save
    @job.job_type = new_job_type
  end
  if save_successful && @job.save
    # redirect to success page
  else
    # render new/edit with error messages
  end
end

En procédant ainsi, vous ne créez un nouveau type de travail que si l'utilisateur soumet réellement le formulaire de travail, ce qui est bien.

Utilisez le modèle save_successful si vous souhaitez appliquer des validations sur le JobType, comme un nom unique. L'enregistrement échouera ensuite si l'utilisateur tente d'enregistrer avec un type de travail existant. Vous pouvez également simplement sélectionner celui existant pour eux, mais je vous laisse le soin si vous choisissez de le faire.

Encore une fois, tout cela suit le même modèle que vous utilisez maintenant, juste un nouveau champ de texte et un peu plus de traitement dans le contrôleur.

Si vous le souhaitez, je peux détailler la réponse à votre question en termes d'utilisation des méthodes AJAX pour que cela fonctionne, car les étapes, bien que beaucoup plus longues, sont assez déterministes, mais c'est probablement exagéré pour votre cas d'utilisation. Cela dit, je déteste ne pas vraiment répondre à la question donnée, quelle que soit mon opinion personnelle sur l'approche, alors faites le moi savoir.

0
GoGoCarl 8 mars 2016 à 02:33

Premièrement , configurez le bouton ou le formulaire dans votre modal pour déclencher la fonction d'envoi.

Deuxièmement , configurez / vérifiez les itinéraires / URL à utiliser pour la méthode AJAX.

En plus de définir la fonction de contrôleur pour enregistrer le nouveau type de travail.

Exemple dans contrôleur :

def create
  job_type = JobType.new
  job_type.title = params[:job_type]
  if job_type.save
   render :json => job_type
  else
   render :json => "some error here."
  end
end

Enfin , créez la fonction AJAX pour envoyer des données.

$("#add_new_job_type").click(function(){
    $.ajax({
        url: '/add_new_job_type',
        type: 'GET', // or POST
        data: {job_type: $("#field_contains_new_value").val()}
    }).done(function(data){
        // Do some validation for checking error response (like if statement)
        // Append the new data (job type to select option tag)
        new_job_type = "<option value="'+data.title+'">" + data.title + "</option>"
        $('#job_job_type_id').append(new_job_type);
        ....
        $("#myModal").modal('hide');
    });

});

Remarques: add_new_job_type utilisé dans AJAX url correspond aux itinéraires personnalisés.

Dans config / routes.rb (itinéraires personnalisés):

match 'add_new_job_type' => 'job_types#add_new_job_type', :via => :post #or :get

Dans votre Contrôleur JobTypes , vous devez avoir:

def add_new_job_type
  job_type = JobType.new
  job_type.title = params[:job_type]
  if job_type.save
   render :json => job_type
  else
   render :json => "some error here."
  end
end

Modifiez le code comme vous le souhaitez.

0
aldrien.h 9 mars 2016 à 01:10