Rails ассоциации не сохраняются в БД - PullRequest
0 голосов
/ 27 февраля 2020

У меня это настроено, но при попытке спасти практикующего отмечается, что записывается в БД. Таблицы пользователей, клиник и практиков. Пользователь должен иметь возможность создавать несколько клиник, и каждый клини c должен иметь возможность добавлять несколько практикующих к указанному c клини c.

Я получаю эту ошибку из журнала

Started PUT "/registration_steps/practitioners_general" for ::1 at 2020-03-01 11:59:29 +0100
Processing by RegistrationStepsController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"KGwLxzNk96QEiY8Enun4cK3Gd3ec0GFsJxFxIq75MDQEGVcpapxTfh7aHR6slMojd3+hQg4MevmPDewRq7vGiA==", "user"=>{"clinics_attributes"=>{"0"=>{"practitioners_attributes"=>{"1583060279301"=>{"practitioner_first_name"=>"sdsad", "practitioner_last_name"=>"sdsadsa", "practitioner_description"=>"sadasda", "practitioner_mail"=>"kvnirvana@yahoo.dk", "practitioner_phone"=>"24210886", "practitioner_website"=>""}}, "id"=>"7"}}}, "commit"=>"Gem", "id"=>"practitioners_general"}
  User Load (1.9ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 95 ORDER BY `users`.`id` ASC LIMIT 1
  ↳ app/controllers/registration_steps_controller.rb:17
Unpermitted parameter: :practitioners_attributes
   (0.2ms)  BEGIN
  ↳ app/controllers/registration_steps_controller.rb:19
  Clinic Load (0.5ms)  SELECT `clinics`.* FROM `clinics` WHERE `clinics`.`user_id` = 95 AND `clinics`.`id` = 7
  ↳ app/controllers/registration_steps_controller.rb:19
   (1.4ms)  COMMIT
  ↳ app/controllers/registration_steps_controller.rb:19
   (0.9ms)  BEGIN
  ↳ app/controllers/registration_steps_controller.rb:20
   (0.2ms)  COMMIT
  ↳ app/controllers/registration_steps_controller.rb:20
Redirected to http://localhost:3000/registration_steps/practitioners_professions
Completed 302 Found in 18ms (ActiveRecord: 5.1ms)


Started GET "/registration_steps/practitioners_professions" for ::1 at 2020-03-01 11:59:29 +0100
Processing by RegistrationStepsController#show as HTML
  Parameters: {"id"=>"practitioners_professions"}
  User Load (0.4ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 95 ORDER BY `users`.`id` ASC LIMIT 1
  ↳ app/controllers/registration_steps_controller.rb:12
  Rendering registration_steps/practitioners_professions.html.erb within layouts/application
  Profession Load (0.5ms)  SELECT `professions`.* FROM `professions` INNER JOIN `user_professions` ON `professions`.`id` = `user_professions`.`profession_id` WHERE `user_professions`.`user_id` = 95
  ↳ app/views/registration_steps/practitioners_professions.html.erb:47
  Profession Load (0.4ms)  SELECT `professions`.* FROM `professions`
  ↳ app/views/registration_steps/practitioners_professions.html.erb:47
  Speciality Load (0.5ms)  SELECT `specialities`.* FROM `specialities` INNER JOIN `user_specialities` ON `specialities`.`id` = `user_specialities`.`speciality_id` WHERE `user_specialities`.`user_id` = 95
  ↳ app/views/registration_steps/practitioners_professions.html.erb:62
  Speciality Load (0.3ms)  SELECT `specialities`.* FROM `specialities`
  ↳ app/views/registration_steps/practitioners_professions.html.erb:62
  Service Load (0.3ms)  SELECT `services`.* FROM `services` WHERE `services`.`user_id` = 95
  ↳ app/views/registration_steps/practitioners_professions.html.erb:81
  Rendered services/_services_fields.html.erb (7.5ms)
  Rendered services/_services_fields.html.erb (6.4ms)
  Rendered registration_steps/practitioners_professions.html.erb within layouts/application (34.6ms)
  Rendered layouts/_header.html.erb (4.1ms)
  Rendered layouts/_footer.html.erb (0.7ms)
Completed 200 OK in 92ms (Views: 88.0ms | ActiveRecord: 2.4ms)

Вот как я пытался заставить его работать до сих пор:

У пользователя много клиник
клиник принадлежит пользователю

в клиниках много практикующих
практикующих принадлежит к клиникам

Я добавил внешний пользовательский ключ для соединения таблицы клиник с таблицей пользователей

Я добавил внешний ключ clini c для соединения таблицы практикующих с таблицей клиник

user.rb

class User < ApplicationRecord        
has_many :clinics, dependent: :destroy
accepts_nested_attributes_for :clinics, reject_if: :all_blank, allow_destroy: true
end

clini c .rb

class Clinic < ApplicationRecord
belongs_to :user
has_many :practitioners
accepts_nested_attributes_for :practitioners, reject_if: :all_blank, allow_destroy: true

end

Practitioner.RB

class Practitioner < ApplicationRecord
belongs_to: clinic
end

добавить внешний ключ клиники для практикующих

class AddClinicReferenceToPratitioners < ActiveRecord::Migration[5.2]
def change
add_reference :practitioners, :clinic, foreign_key: true
end
end

добавить внешний ключ пользователя в клинику

class AddUserReferenceToClinics < ActiveRecord::Migration[5.2]
def change
add_reference :clinics, :user, foreign_key: true
end
end

практикующих врачей. html .rb

      <div class="content">
        <div class="content practitioner">
            <h2 class="page-title">Generel information</h2>
            <%= simple_form_for @user, url: wizard_path, method: :put do |f| %>
                <%= f.simple_fields_for(:clinics) do |p| %>
                    <%= render 'clinics/clinics_fields', :f => p %>
                <% end %>

                <div class="submit-container">
                    <%= f.submit "Gem", :class => 'btn blue' %>
                </div>
            <% end %>
        </div>
    </div>

Clinics / _clinics_fields. html .erb

<%= f.simple_fields_for(:practitioners) do |p| %>
<%= render 'practitioners/practitioners_fields', :f => p %>
<% end %>
<div class="links">
  <%= link_to_add_association 'Add Practitioner', f, :practitioners, :partial => 'practitioners/practitioners_fields' %>
</div>

практикующих / практикующих поля. html .erb

<div class="nested-fields">
  <div class="basic-section">

    <div class="info-group">
      <div class="field-group">
        <div class="field text-field">

          <%= f.input_field :practitioner_first_name, required: true, autofocus: true, autocomplete: "Fornavn", placeholder: "Fornavn" %>
        </div>
        <div class="field text-field">
          <%= f.input_field :practitioner_last_name, required: true, autofocus: true, autocomplete: "Efternavn", placeholder: "Efternavn" %>
        </div>
      </div>

    </div>
  </div>
  <div class="about-section">
    <div class="field text-field">
      <%= f.input_field :practitioner_description, :as => :text, :input_html => { 'rows' => 5}, autofocus: true, autocomplete: "Beskrivelse af behandler", placeholder: "Beskrivelse af behandler" %>
    </div>

  </div>
  <div class="field-group contact-section">
    <div class="field text-field">
      <%= f.input_field :practitioner_mail, input_html: { autocomplete: 'email' }, autofocus: true, placeholder: "E-mail" %>
    </div>
    <div class="field text-field">
      <%= f.input_field :practitioner_phone, autofocus: true, autocomplete: "Tlf. nr.", placeholder: "Tlf. nr." %>
    </div>
    <div class="field text-field">
      <%= f.input_field :practitioner_website, required: false, autofocus: true, autocomplete: "Hjemmeside", placeholder: "Hjemmeside" %>
    </div>
  </div>

</div>

registration_steps_controller.rb

class RegistrationStepsController < ApplicationController

    include Wicked::Wizard
    steps :company_general, :company_images, :practitioners_general, :practitioners_professions, :practitioners_educations

    def create
      @practitioner = Practitioner.new(params[:practitioners])
      @practitioner.save
    end

    def show
     @user = current_user    
    render_wizard 
    end

    def update
      @user = current_user
      # Change @user.attributes(user_params) by @user.update_attributes(user_params)
      @user.update_attributes(user_params)
      render_wizard @user
    end



private
def user_params
  params.require(:user)
  .permit(:gender, :first_name, :last_name, :email, :password, :password_confirmation, :phone, 
    :clinic_logo, 
    :practitioner_image,
    :public_health_insurance, 
    clinic_images: [], 
    profession_ids: [], 
    speciality_ids: [], 
    services_attributes: [:id, :description, :name, :duration, :price, :_destroy], 
    educations_attributes: [:id, :name, :place, :year, :_destroy],
    membership_ids: [],
    awards_attributes: [:id, :name, :year, :_destroy],
    clinics_attributes: [:id, :clinic_logo, :clinic_name, :clinic_address, :clinic_zip_code, :clinic_municipality, :clinic_about, :clinic_mail, :clinic_phone, :clinic_website, :clinic_city, :_destroy],
    practitioners_attributes: [:id, :practitioner_first_name, :practitioner_last_name, :practitioner_description, :practitioner_mail, :practitioner_phone, :practitioner_website, :_destroy])

end

end

ApplicationController.rb

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

    before_action :authenticate_user!, :configure_permitted_parameters, if: :devise_controller?

    protected

    def configure_permitted_parameters
      devise_parameter_sanitizer.permit(:sign_up, keys: 
        [:gender, :first_name, :last_name, :email, :password, :password_confirmation, :phone, 
        :clinic_logo, 
        :practitioner_image,
        :public_health_insurance, 
        clinic_images: [], 
        profession_ids: [], 
        speciality_ids: [], 
        services_attributes: [:id, :description, :name, :duration, :price, :_destroy], 
        educations_attributes: [:id, :name, :place, :year, :_destroy],
        membership_ids: [],
        awards_attributes: [:id, :name, :year, :_destroy],
        clinics_attributes: [:id, :clinic_logo, :clinic_name, :clinic_address, :clinic_zip_code, :clinic_municipality, :clinic_about, :clinic_mail, :clinic_phone, :clinic_website, :clinic_city, :_destroy],
        practitioners_attributes: [:id, :practitioner_first_name, :practitioner_last_name, :practitioner_description, :practitioner_mail, :practitioner_phone, :practitioner_website, :_destroy]])


        devise_parameter_sanitizer.permit(:account_update, keys: 
          [:gender, :first_name, :last_name, :email, :password, :password_confirmation, :phone, 
            :clinic_logo, 
            :practitioner_image, 
            :public_health_insurance, 
            clinic_images: [], 
            profession_ids: [], 
            speciality_ids: [], 
            services_attributes: [:id, :description, :name, :duration, :price, :_destroy], 
            educations_attributes: [:id, :name, :place, :year, :_destroy],
            membership_ids: [],
            awards_attributes: [:id, :name, :year, :_destroy],
            clinics_attributes: [:id, :clinic_logo, :clinic_name, :clinic_address, :clinic_zip_code, :clinic_municipality, :clinic_about, :clinic_mail, :clinic_phone, :clinic_website, :clinic_city, :_destroy],
            practitioners_attributes: [:id, :practitioner_first_name, :practitioner_last_name, :practitioner_description, :practitioner_mail, :practitioner_phone, :practitioner_website, :_destroy]])



    end


    def after_sign_in_path_for(resource)
      rails_admin_path
    end

  end

rout.rb

Rails.application.routes.draw do
  mount RailsAdmin::Engine => '/admin', as: 'rails_admin'

  devise_for :users, controllers: {:registrations => "users/registrations" 
  }

  resources :registration_steps
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
  root 'pages#index' 
  get 'about', to: 'pages#about'
  get 'team', to: 'pages#team'
  get 'faqs', to: 'pages#faqs'
  get 'faqspractitioners', to: 'pages#faqspractitioners'
  get 'faqsusers', to: 'pages#faqsusers'
  get 'login', to: 'pages#login'
  get 'signup', to: 'pages#signup'
  get 'search', to: 'pages#search'


  get "userprofiles/user_info" => "userprofiles#user_info", as: "user_info"
  get "userprofiles/clinic_info" => "userprofiles#clinic_info", as: "clinic_info"
  get "userprofiles/practitioner_info" => "userprofiles#practitioner_info", as: "practitioner_info"


  patch "userprofiles/user_info" => "userprofiles#update"
  patch "userprofiles/clinic_info" => "userprofiles#update"
  patch "userprofiles/practitioner_info" => "userprofiles#update"




  devise_scope :user do 
    scope module: :users do
      resources :registrations, only: [] do
        member do
          delete :delete_image_attachment
        end
      end
    end
  end

end

Ответы [ 3 ]

0 голосов
/ 28 февраля 2020

Изменение

user.rb

class User < ApplicationRecord    
    accepts_nested_attributes_for :practitioners, reject_if: :all_blank, allow_destroy: true

    has_many :clinics, dependent: :destroy
    accepts_nested_attributes_for :clinics, reject_if: :all_blank, allow_destroy: true
end

clini c .rb

class Clinic < ApplicationRecord
    belongs_to :user
    has_many :practitioners
end

Practitioner.rb

class Practitioner < ApplicationRecord
    belongs_to: clinic
end

TO

user.rb

class User < ApplicationRecord    
  has_many :clinics, dependent: :destroy
  accepts_nested_attributes_for :clinics, reject_if: :all_blank, allow_destroy: true
    end

clini c. rb

class Clinic < ApplicationRecord
    belongs_to :user
    has_many :practitioners
    accepts_nested_attributes_for :practitioners, reject_if: :all_blank, allow_destroy: true
    end

Practitioner.RB

class Practitioner < ApplicationRecord
    belongs_to: clinic
end

Причина в том, что вы используете accepts_nested_attributes_for для моделей, которые has_many в текущей модели ,

Таким образом, пользователь должен принимать параметры для clinics, а clinics должен принимать параметры для practitioners.

Обновление

Вы не должны использовать это

<div class="content">
<div class="content practitioner">
<h2 class="page-title">Generel information</h2>

<%= simple_form_for @user, url: wizard_path, method: :put do |f| %>

<%= f.simple_fields_for(:clinics) do |p| %>
<%= render 'clinics/clinics_fields', :f => p %>
<% end %>
</div>
<div class="submit-container">
<%= f.submit "Gem", :class => 'btn blue' %>

</div>
<% end %>

</div>

Это должно быть что-то вроде

Practitioners_general. html .rb

<div class="content">
    <div class="content practitioner">
        <h2 class="page-title">Generel information</h2>
        <%= simple_form_for @user, url: wizard_path, method: :put do |f| %>
            <%= f.simple_fields_for(:clinics) do |p| %>
                <%= render 'clinics/clinics_fields', :f => p %>
            <% end %>
            <div class="submit-container">
                <%= f.submit "Gem", :class => 'btn blue' %>
            </div>
        <% end %>
    </div>
</div>

_clinics_fields. html .rb

            <%= f.simple_fields_for(:practitioners) do |p| %>
                <%= render 'practitioners/practitioners_fields', :f => p %>
            <% end %>

_practitioners_fields. html .rb

<div class="nested-fields">
  <div class="basic-section">
  ...
  ...
  ...
  </div>
</div>

Вам необходимо лучше понять концепцию работы вложенных параметров

def user_params
  params.require(:user)
        .permit(
          ...user attributes related params
          clinics_attributes: [
            ...clinics attributes related params
            practitioners_attributes: [
              ...practitioner attributes related params
            ]
          ])
end

clinics_attributes должен быть частью user_params, поскольку clinic принадлежит пользователю. Точно так же practitioners_attributes будет частью clinic_params

0 голосов
/ 02 марта 2020

Я исправил это, изменив параметры с

    clinics_attributes: [:id, :clinic_logo, :clinic_name, :clinic_address, :clinic_zip_code, :clinic_municipality, :clinic_about, :clinic_mail, :clinic_phone, :clinic_website, :clinic_city, :_destroy],
        practitioners_attributes: [:id, :practitioner_first_name, :practitioner_last_name, :practitioner_description, :practitioner_mail, :practitioner_phone, :practitioner_website, :_destroy])

end

на

clinics_attributes: [:id, :clinic_logo, :clinic_name, :clinic_address, :clinic_zip_code, :clinic_municipality, :clinic_about, :clinic_mail, :clinic_phone, :clinic_website, :clinic_city, :_destroy,
    practitioners_attributes: [:id, :practitioner_first_name, :practitioner_last_name, :practitioner_description, :practitioner_mail, :practitioner_phone, :practitioner_website, :_destroy]])

end
0 голосов
/ 27 февраля 2020

См. Это:

Unpermitted parameter: :practitioners

... в журнале вашего сервера?

У вас есть Parameters, который выглядит следующим образом:

{
  "user"=>{
    "practitioners"=>{
      "practitioner_image"=>        #<ActionDispatch::Http::UploadedFile:0x00007f811c002dd8 ...>, 
      "practitioner_first_name"=>   "Kasper", 
      "practitioner_last_name"=>    "Valentin", 
      "gender"=>                    "Mand", 
      "practitioner_description"=>  "asasdas", 
      "public_health_insurance"     =>"1", 
      "practitioner_mail"           =>"kvnirvana@yahoo.dk", 
      "practitioner_phone"          =>"24210886", 
      "practitioner_website"        =>"www.yahoo.dk"
    }
  }, 
  "commit"=>"Gem", 
  "id"=>"practitioners_general"
}

В вашем user_params, у вас есть это:

def user_params
  params.require(:user)
  .permit(
    ...,
    practitioners_attributes: [
      :id, 
      :practitioner_first_name, 
      :practitioner_last_name, 
      :practitioner_description, 
      :practitioner_mail, 
      :practitioner_phone, 
      :practitioner_website, 
      :_destroy
    ]
  )
end 

Видите? Вы разрешаете practitioners_attributes, но у вашего Parameters есть practitioners. Поскольку вы не разрешаете practitioners, он отклоняется как Unpermitted parameter, что именно то, что вам говорят ваши файлы журнала.

Если вы хотите разрешить practitioner_attributes, то сделайте что-то более похожее на:

<%= f.simple_fields_for(:practitioner_attributes) do |p| %>
  <%= render 'practitioners/practitioners_fields', :f => p %>
<% end %>

Если вы хотите оставить practitioners в вашем Parameters, тогда сделайте что-то еще, например:

def user_params
  params.require(:user)
  .permit(
    ...,
    practitioners: [
      :id, 
      :practitioner_first_name, 
      :practitioner_last_name, 
      :practitioner_description, 
      :practitioner_mail, 
      :practitioner_phone, 
      :practitioner_website, 
      :_destroy
    ]
  )
end

Суть в том, что все, что есть в вашем Parameters, должно совпадать с тем, что в вашем permit утверждении. В настоящее время они не совпадают, поэтому practitioners является недопустимым параметром.

...