Rails злой волшебник с JavaScript

Я хочу создать мастера в JS.

steps   :first_step,
        :second_step

В моем 'controller_step'

def show
        case step
            when :first_step
                @r  = R.new
            when :second_step

            end
        render_wizard
end

def update
        case step
            when :first_step
                @r = R.new(r_params)
            when :second_step

            end

        render_wizard @r
end

У меня проблемы после обновления первого шага. Я получаю следующее сообщение об ошибке:

"Отсутствует шаблон controller_step/second_step, application/second_step с {:locale=>[:en],:format =>[:html],: варианты =>[],: обработчики => [: эрб,: строитель,: сырье,:ruby,:coffee,:jbuilder]}. ".

Как я могу принудительно загрузить JS Templete? Я бы загрузил "second_step.js.erb".

Я пытался изменить метод обновления:

respond_to do |format|
  format.js { render :js => ( render_wizard @r ) }  
end

Конечно, я получаю следующую ошибку:

"AbstractController:: DoubleRenderError in... Controller # update Рендеринг и / или перенаправление вызывались несколько раз в этом действии. Обратите внимание, что вы можете вызывать только перенаправление рендеринга ИЛИ и не более одного раза для каждого действия. Также обратите внимание, что ни перенаправление, ни рендеринг прекратить выполнение действия, поэтому, если вы хотите выйти из действия после перенаправления, вам нужно сделать что-то вроде "redirect_to(...) и вернуть".

Я также пытался изменить код (в обновлении):

respond_to do |format|
   format.js { render :js => ( render_wizard @room_types and return ) } 
end

Я получаю ту же ошибку ( ... application/second_step с {:locale=>[:en],:format => [: html]....)

PS

С учетом первого шага:

<%= form_for(@r, url: wizard_path, method: :put, remote: true) do |f| %>
   ....
   <%= f.submit "Submit", class: "btn btn-default" %>
<% end %>

Как мне исправить? заранее спасибо

2 ответа

Решение

#render_wizard метод, определенный в Wicked::Controller::Concerns::RenderRedirect это метод обертки вокруг ActionController::Base#render метод. Он принимает хэш опций и передает его в обычный контроллер #render метод.

Это исходный код из библиотеки Wicked:

def render_wizard(resource = nil, options = {})
  ...

  if @skip_to
    ...
  else
    render_step wizard_value(step), options
  end
end

def render_step(the_step, options = {})
  if the_step.nil? || the_step.to_s == Wicked::FINISH_STEP
    ...
  else
    render the_step, options #<-- Here
  end
end

Ваш код:

respond_to do |format|
  format.js { render :js => ( render_wizard @r ) }  
end

в основном делает:

respond_to do |format|
  format.js { render :js => ( render @r ) }  
end

который фактически вызывает метод рендеринга дважды.

Как это ищет .html шаблон, а не .js.erb один, попробуйте добавить formats: 'js' опция для метода render_wizard. Следует добавить ['JS'] к :formats=>[:html] мы видим в Missing template сообщение об ошибке.

respond_to do |format|
  format.js { render_wizard(@r, formats: 'js') }
end

также убедитесь, что имя файла шаблона соответствует соглашению с rails и начните с _, (То есть: _second_step.js.erb)


Насчет двойной ошибки рендера, вы правы. Вы должны вернуться из контроллера #show или же #update метод и предотвратить дальнейший код от вызова #render метод во второй раз. Вы, кажется, уже исправили эту проблему.

EDIT # 1

Похоже, что вы можете вызвать этот метод непосредственно в вашем контроллере..:

def render_step(the_step, options = {})
  # Wicked::FINISH_STEP = "wicked_finish"
  if the_step.nil? || the_step.to_s == Wicked::FINISH_STEP
    redirect_to_finish_wizard options
  else
    render the_step, options
  end
end

я верю the_step будет имя частичного. Я думаю, что вы должны быть в состоянии позвонить #render_step метод от вашего контроллера.

Вы можете сделать:

def show
  respond_to do |f|
    f.js do
      case step
      when :first_step
          @r  = R.new
          render_step(step) and return
      when :second_step
        ...
      end
    end
  end
end

Я решил таким образом:

в модели r:

validates   :x, presence: true

в шаговом контроллере:

...
steps   :first_step,
        :second_step,
        :finish_step
...

def show
    case step
        when :first_step
            @room_types  = R.new
        end

    render_wizard       
end

def update
   case step
      when :view_new_room_type_step
         @r = R.create(r_params)
      when :view_desc_step
         @r = R.find(params[:r][:id])
         @r.update(r_params)
      end

    respond_to do |format|
       if !@r.errors.any?
          format.js { !next_step?(:finish_step) ? ( render next_wizard_path ) : ( redirect_to_finish_wizard ) }
       else
          format.js { render wizard_path, r: @r }
       end
    end
end 

private
        ...

        def redirect_to_finish_wizard
            redirect_to r_index_path , notice: "Ok"
        end

в first_step.js.erb

$("#modal").html("<%= escape_javascript(render 'form_first_step') %>")

в _form_first_step.html.erb:

<% if @r.errors.any? %>
   <div class="alert fade in alert-danger alert-dismissable"><button aria-hidden="true" class="close" data-dismiss="alert" type="button">&#215;</button>
      <ul>
         <% @r.errors.full_messages.each do |msg| %>
            <%= content_tag :li, msg, :id => "error_#{msg}" if msg.is_a?(String) %>
          <% end %>
      </ul>
    </div>
<% end %>

<%= form_for(@room_types, url: wizard_path, method: :put, remote: true) do |f| %>
   ...
<% end %>

во второй форме (второго этапа):

<%= form_for(@room_types, url: wizard_path(:second_step), method: :put, remote: true) do |f| %>
    ....
    <%= f.hidden_field :id %>
<% end %>

Идея: для проверки данных на этапах вы можете использовать https://github.com/gustaflindqvist/jquery-form-validator-rails

Другие вопросы по тегам