Ошибка назначения внешнего ключа Rails - PullRequest
0 голосов
/ 05 мая 2020

Я создаю простой рабочий процесс, в котором после регистрации publisher может создать newsletter. Для этого информационного бюллетеня необходимы три части информации: title, description и publisher_id (т. Е. Создатель). У меня двоякий вопрос:

  1. Каков «правильный» способ установить publisher_id, учитывая, что newsletters будет содержать posts внутри них, а Rails рекомендует не вкладывать ресурсы более чем на один уровень (т. Е. Я не должен вкладывать информационный бюллетень в издателя)?
  2. Если я в целом подхожу к нему правильно (см. Ниже), как мне передать publisher_id и что я делаю не так?

Рабочий процесс выглядит следующим образом:

  • Создайте издателя и установите session[:id] на @publisher.id.
  • Перенаправление на информационный бюллетень new просмотр.
  • После создания информационного бюллетеня установите publisher_id информационного бюллетеня на session[:id].

При переходе к '/ newsletters / new ', я вижу следующую ошибку:

Started GET "/newsletters/new" for ::1 at 2020-05-04 15:53:22 -0700
Processing by NewslettersController#new as HTML
"<ActionController::Parameters {\"controller\"=>\"newsletters\", \"action\"=>\"new\"} permitted: false>"
  Rendering newsletters/new.html.erb within layouts/application
  Rendered newsletters/new.html.erb within layouts/application (Duration: 2.3ms | Allocations: 738)

И после отправки «Создать информационный бюллетень» я вижу следующую ошибку:

ActiveModel::ForbiddenAttributesError (ActiveModel::ForbiddenAttributesError):

app/controllers/newsletters_controller.rb:21:in `create'
Started POST "/newsletters" for ::1 at 2020-05-04 15:58:34 -0700
   (0.0ms)  SELECT sqlite_version(*)
Processing by NewslettersController#create as JS
  Parameters: {"authenticity_token"=>"XXX", "newsletter"=>{"title"=>"Newsletter 1", "description"=>"Description content"}, "commit"=>"Create Newsletter"}
Completed 500 Internal Server Error in 11ms (ActiveRecord: 1.0ms | Allocations: 7085)

publishers_controller. rb

class PublishersController < ApplicationController
    def create
        @publisher = Publisher.new(publisher_params)
        if @publisher.save!
            session[:id] = @publisher.id
            redirect_to new_newsletter_path
        else
            render 'new'
        end
    end

    private
        def publisher_params
            params.require(:publisher).permit(:email, :password)
        end
end

newsletters_controller.rb

class NewslettersController < ApplicationController
    def new
        @newsletter = Newsletter.new
    end

    def create
        @newsletter = Newsletter.new(newsletter_params)

        if @newsletter.save!
            redirect_to @newsletter
        else
            render 'new'
        end
    end

    private
        def newsletter_params
            params.require(:newsletter).permit(:title, :description).merge(publisher_id: session[:id])
        end
end

/ newsletters / new. * 105 5 * .erb

<%= form_with model: @newsletter, url: newsletters_path do |form| %>
  <p>
    <%= form.label :title %><br>
    <%= form.text_field :title %>
  </p>

  <p>
    <%= form.label :description %><br>
    <%= form.text_area :description %>
  </p>

  <p>
    <%= form.submit %>
  </p>
<% end %>

1 Ответ

2 голосов
/ 05 мая 2020

Вы неправильно поняли, что руководство rails подразумевает под «вложением ресурсов на глубину более одного уровня» - на самом деле это означает, что это нормально:

/publishers/1/newsletters/new

Это один уровень вложенности, и вложение обеспечивает очень полезная контекстная информация. Хотя они выглядят подозрительно:

/publishers/1/newsletters/2
/publishers/1/newsletters/3/replies/new

В обоих случаях у нас есть два уровня вложенности, которые должны иметь возможность достичь вложенного ресурса, не переходя через publishers.

/newsletters/2
/newsletters/3/replies/new

Также если вы хотите добавить значения из сеанса или где-то еще, тогда параметры ha sh при создании записи используйте блок или вместо этого создайте запись вне ассоциации:

class NewslettersController < ApplicationController
  def create 
    @newsletter = Newsletter.new(newsletter_params) do |newletter|
      newsletter.publisher = current_publisher
    end
    # or
    # @newsletter = current_publisher.newsletters(newsletter_params)

    # save! will raise an exception if the record is not valid
    # that is NOT what you want here
    if @newsletter.save 
      redirect_to @newsletter
    else
        render 'new'
    end
  end
end

Это делает его гораздо более очевидным что откуда исходит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...