Передача значения переменной из функции js в представление rails (динамический выбор) - PullRequest
0 голосов
/ 19 октября 2010

Я использую метод Райана , чтобы динамически добавлять и удалять вложенные поля модели через JavaScript с помощью jQuery.

Есть 4 модели: клиент, c_person; проект, p_person. И связи «один ко многим»: у клиента много c_people, а в проекте много p_people (это люди со стороны клиента, но они принадлежат проекту).

Итак, у меня следующая проблема:

Когда я использую вспомогательный метод "link_to_add_fields" в моем представлении, мне нужно передать другой параметр (current_client_id), который зависит от того, какой клиент в данный момент выбран в поле выбора.

<!-- new.html.erb -->
<p>
<%= f.label :client_id %></br>
<%= f.collection_select :client_id, Client.order("title"), :id, :title %>
</p>
<p>
<%= f.fields_for :p_people do |builder| %>
<%= render "p_person_fields", :f => builder %>
<% end %>
</p>
<p><%= link_to_add_fields "Add Person", f, :p_people, current_client_id %></p>

Мне нужно, чтобы динамически изменить коллекцию для переменной @people в вспомогательном методе,

# application_helper.rb
def link_to_add_fields(name, f, association, current_client_id)
    new_object = f.object.class.reflect_on_association(association).klass.new
    @people = CPerson.where(:client_id => current_client_id).order(:name) unless current_client_id.blank?
    fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder|
      render(association.to_s.singularize + "_fields", :f => builder)
    end
    link_to_function(name, h("add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")"))
end

чтобы наконец использовать его частично:

<!-- _p_person_fields.html.erb -->
<div class="fields">
<p>
<%= f.collection_select :content, @people, :name, :name %>
<%= f.hidden_field :_destroy %>
<%= link_to_function "Remove", "remove_fields(this)" %>
</p>
</div>

Вот простая функция js для получения значения current_client_id, но я не знаю, как передать его в метод view или вспомогательный метод.

// application.js
function current_client_id() {
var current_client_id = $("select#client_id :selected").val();
}

Я ценю вашу помощь! Может быть, есть лучшее решение?

Ответы [ 3 ]

0 голосов
/ 13 ноября 2010

Я нашел лучший способ назначить людей на проект - использовать опцию множественного выбора. Это позволяет не использовать вложенные поля модели.

1.Используйте has_and_belongs_to_many связь между двумя моделями: c_person и project.

2.Создать таблицу соединений:

class CreateCPeopleProjects < ActiveRecord::Migration
  def self.up
    create_table :c_people_projects, :id => false do |t|
      t.references :project
      t.references :c_person  
    end  
  end

  def self.down
    drop_table :c_people_projects
  end
end

3. Модифицируйте new.html.erb и частичное.

<!-- new.html.erb -->
<p>
<%= f.label :client_id, "Client" %><br />
<%= f.collection_select :client_id, @clients, :id, :title %>
</p>
<div id="people">
<%= render "c_people" %>
</div>

<!-- _c_people.html.erb -->
<p>
<%= fields_for :project do |f| %>
 <% if @update_people.blank? %>
 <%= f.collection_select :c_person_ids, @people, :id, :name, {:selected => @project.c_person_ids}, {:multiple => true, :name => "project[c_person_ids][]"} %>
 <% else %>
 <%= f.collection_select :c_person_ids, @update_people, :id, :name, {}, {:multiple => true, :name => "project[c_person_ids][]"} %>
 <% end %>
<% end %>
</p>

4.Добавьте функцию js, чтобы получить текущее значение идентификатора клиента, отправить его в projects_controller и заменить частичное новым набором.

jQuery(function($) {
 $(function() {
  $("#project_client_id").change(function() {
  var client_id = $("select#project_client_id :selected").val();
  if (client_id == "") {client_id = "0";}
  $.get("/projects/update_people/" + client_id, function(data){
   $("#people").html(data);
  })
  return false;
  });
 });
})

5.Добавить метод projects_controller для динамического изменения коллекции для людей. И одна строка для обновления действия (для обновления объектов nil).

  def update
    @project = Project.find(params[:id])
    params[:project][:c_person_ids] ||= []

    respond_to do |format|
      if @project.update_attributes(params[:project])
        format.html { redirect_to(@project, :notice => 'Project was successfully updated.') }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @project.errors, :status => :unprocessable_entity }
      end
    end
  end

  def update_people
    @update_people = CPerson.where(:client_id => params[:id]).order(:name) unless params[:id].blank?
    render :partial => "c_people"
  end

6.Не забывайте про маршруты: match "/projects/update_people/:id" => "projects#update_people"

0 голосов
/ 21 января 2011

Если вы используете Rails 3 , то вы должны удалить «h (» в application_helper.rb:

link_to_function(name, h("add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")"))

до

link_to_function(name, "add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")")
0 голосов
/ 29 октября 2010

Одна вещь, которая мне не нравится в этом, это то, что вы используете логику в помощнике вида, который действительно принадлежит вашему контроллеру.

Возможно, лучшим подходом было бы сделать AJAX-вызов контроллерас current_client_id.Затем этот контроллер может получить объект @people и отправить обратно шаблон js.erb, где вы можете добавить частичное к вашему представлению.Или он может отправить обратно объект JSON, и обработчик вашего вызова AJAX создаст новые элементы для добавления в DOM.

...