Search code examples
ruby-on-railsrubyroutessimple-form

ActionViewError:Missing Template inside controller method


So, i have 2 forms. In one of them, im submitting the form to the method "create", the default one created with resources:

resources :correlation_engine_rules 

In this form, i just link the form with the path via simple_form:

<%= simple_form_for(:correlation_engine_rule, url: correlation_engine_rules_path, :html => { :remote => true, :method => :post }) do |f| %>

Now, if i submit, im calling the method called "create" in my controller:

def create
    ...things happening...

    respond_to do |format|
      if @rule.save
        format.html { redirect_to correlation_engine_rules_path(value: @cep_status), notice: "#{I18n.t('controllers.rule_created')}" }
        format.js { flash[:notice] = "#{I18n.t('controllers.rule_created')}" }
        format.json { head :no_content }
      else
        format.html do
          redirect_to correlation_engine_rules_path(@rule),
                      alert: @rule.errors.full_messages.map { |msg| "<li>#{msg}</li>" }.join
        end
        format.js
        format.json { render json: @rule.errors, status: :unprocessable_entity }
      end
    end
  end

The rule is saved and the page is redirect to that path. This is working. Now, i wanted to have a new form, with another method controller to process these new fields.

So, i created new routes:

resources :correlation_engine_rules do
      get :basic_rule_2, on: :collection
      post :create_basic_rule_2, on: :collection
end

And then i associated the new form with my new method controller (create_basic_rule_2):

<%= simple_form_for(:correlation_engine_rule, url: create_basic_rule_2_correlation_engine_rules_path, :html => { :remote => true, :method => :post }) do |f| %>

When i submit, the controller is called correctly, the problem comes when doing the exact same redirect as before. Here the redirect fails and it tried to render a view called "create_basic_rule_2", which i don't understand. I'm telling him to redirect to correlation_engine_rules_path as before.

def create_basic_rule_2
    ...things happening...

    respond_to do |format|
      if @rule.save
        format.html { redirect_to correlation_engine_rules_path(value: @cep_status), notice: "#{I18n.t('controllers.rule_created')}" }
        format.js { flash[:notice] = "#{I18n.t('controllers.rule_created')}" }
        format.json { head :no_content }
      else
        Rails.logger.error "\n\n\n\ NO GUARDADO"
        format.html do
          redirect_to correlation_engine_rules_path(@rule),
                      alert: @rule.errors.full_messages.map { |msg| "<li>#{msg}</li>" }.join
        end
      end
    end
  end

What bugges me is that is the exact same code, and the path is the same wherever you are, so why create is not render a view called "create", but my method create_basic_rule_2 is trying to render a view called "create_basic_rule_2?

Here is the error that i get:

<ActionView::MissingTemplate: Missing template correlation_engine_rules/create_basic_rule_2, application/create_basic_rule_2 with {:locale=>[:es, :en], :formats=>[:js, :html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :jbuilder]}. Searched in:
  * "/opt/rb/var/www/rb-rails/lib/modules/vault/app/views"
  * "/opt/rb/var/www/rb-rails/lib/modules/social/app/views"
  * "/opt/rb/var/www/rb-rails/lib/modules/monitor/app/views"
  * "/opt/rb/var/www/rb-rails/lib/modules/location/app/views"
  * "/opt/rb/var/www/rb-rails/lib/modules/ips/app/views"
  * "/opt/rb/var/www/rb-rails/lib/modules/flow/app/views"
  * "/opt/rb/var/www/rb-rails/lib/modules/correlation_engine_rule/app/views"
  * "/opt/rb/var/www/rb-rails/app/views"
  * "/usr/local/rvm/gems/ruby-2.1.2/gems/devise-3.5.10/app/views"
>

Solution

  • If you setup a MRE and check the request type (hint its on the first line of the logs) of the request you can see that the issue is actually pretty straight forward:

    <%= simple_form_for(:correlation_engine_rule, url: create_basic_rule_2_correlation_engine_rules_path, :html => { :remote => true, :method => :post }) do |f| %>
    

    Rails UJS defaults to sending those pesky application/javascript AJAX requests when you set the data-remote="true" option.

    Which means that the controller is actually executing this block:

    format.js { flash[:notice] = "#{I18n.t('controllers.rule_created')}" }
    

    Since it does not render or redirect rails will implicitly try to find a template named create_basic_rule_2. Redirecting in format.js response won't actually do anything since its an AJAX request.

    Instead you want to set remote: false:

    <%= simple_form_for(:correlation_engine_rule, url: create_basic_rule_2_correlation_engine_rules_path, html: { remote: false, method: :post }) do |f| %>
    

    Which will just submit the form normally and trigger the format.html block.

    If you really wanted to send an ajax request and cause a redirect you would have to create a template and set window.location:

    # views/controller_name/correlation_engine_rule.js.erb
    window.location = '/new_location'