Rails 4.0 с настройкой. Вложенные атрибуты Непересекаемые параметры
Я работаю над веб-приложением с помощью Devise и Rails 4. У меня есть модель User, которую я расширил с помощью двух дополнительных полей формы, которые, когда пользователь подписывается, могут также представить свои фамилии/имена. (на основе http://blog.12spokes.com/web-design-development/adding-custom-fields-to-your-devise-user-model-in-rails-4/). Теперь я хочу добавить модель Institution. Эта модель has_many: пользователи и пользователь принадлежит к: учреждению. Я хочу, чтобы иметь возможность зарегистрировать название учреждения в той же форме, я зарегистрирую пользователя. Я знаю, что мне нужна вложенная переменная в моей модели Institution, так как это родительский элемент, который я покажу немного. Когда я пытаюсь зарегистрировать пользователя, я попадаю в консоль: Unpermited parameters: Institutions.
Мой намек заключается в том, что я не могу обновить родительский класс (Institution) на основе моего дочернего класса (User). Может ли быть решение этого? Или кто-нибудь испытал что-то подобное?
class Institutions < ActiveRecord::Base
has_many :users,
accepts_nested_attributes_for :users
end
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :institution
end
registrations/new.html.erb Здесь у меня есть вложенная форма
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
.
.
<%= f.fields_for :institutions do |i| %>
<p><%= i.label :name %><br />
<%= i.text_field :institutions_attr %></p>
<% end %>
Основываясь на учебнике, который я связал ранее, я создал новый User :: ParameterSanitizer, который наследуется от Devise :: ParameterSanitizer и переопределяет метод sign_up
следующим образом:
Библиотека /user_sanitizer.rb
private
def sign_up
default_params.permit(:first_name, :last_name ,:email, :password, :password_confirmation, :current_password, institutions_attributes: [:id, :name])
end
Наконец, мой application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
protected
def devise_parameter_sanitizer
if resource_class == User
User::ParameterSanitizer.new(User, :user, params)
else
super
end
end
end
Спасибо за чтение!
Выход параметров консоли:
{"utf8"=>"✓",
"authenticity_token"=>"JKuN6K5l0iwFsj/25B7GKDj7WEHR4DO3oaVyGxGJKvU=",
"user"=>{"email"=>"[email protected]",
"first_name"=>"abc",
"last_name"=>"xyz",
"institutions"=>{"name"=>"Government"},
"password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]"},
"commit"=>"Sign up"}
РЕДАКТИРОВАТЬ
Как было предложено, я добавил
params.require(resource_name).permit( :email, :first_name, :last_name, institution: [:name], :password, :password_confirmation ) and I get an *error syntax error, unexpected ',', expecting => ...nstitution: [:name], :password, :password_confirmation )*
НО, если я перередактирую
params.require(resource_name).permit( :email, :first_name, :last_name, :password, :password_confirmation, institution: [:name] )
Я получаю NO синтаксическую ошибку, но я получаю параметры Unpermited: Учреждения в запросе.
Я убежден, что это происходит потому, что Пользователь является дочерней организацией. Однако мне не удалось найти работу.
Ответы
Ответ 1
конфиг /routes.rb
Создайте свой собственный регистрационный контроллер, как это... (см. Документацию по разработке деталей вышеперечисленных контроллеров здесь...)... это более элегантный способ, а не делать это через ApplicationController
devise_for :users, controllers: {registrations: 'users/registrations'}
приложение/контроллеры/пользователи /registrations_controller.rb
Переопределите новый метод для создания Profile
связанного с моделью User
как показано ниже: запустите метод configure_permitted_parameters
перед тем, чтобы дезинфицировать параметры (обратите внимание, как добавить вложенные параметры)
class Users::RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters
# GET /users/sign_up
def new
# Override Devise default behaviour and create a profile as well
build_resource({})
resource.build_profile
respond_with self.resource
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u|
u.permit(:email, :password, :password_confirmation, :profile_attributes => :fullname)
}
end
end
дб/мигрирует/xxxxxxxxxxxxxx_create_profiles.rb
Это миграция, которая генерирует модель Profile
(обратите внимание на ссылку на User
)... этот примерный профиль сохраняет только fullname
в качестве расширения User
но не стесняйтесь добавлять по своему желанию!
class CreateProfiles < ActiveRecord::Migration
def change
create_table :profiles do |t|
t.references :user
t.string :fullname
t.timestamps
end
end
end
приложение/модели /user.rb
class User < ActiveRecord::Base
# Associations
has_one :profile, dependent: :destroy, autosave: true
# Allow saving of attributes on associated records through the parent,
# :autosave option is automatically enabled on every association
accepts_nested_attributes_for :profile
# Devise
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
приложение/модели /profile.rb
class Profile < ActiveRecord::Base
# Associations
belongs_to :user
# Validations
validates :fullname, presence: true
end
приложение/просмотров/изобрести/регистрация /new.html
<% resource.build_profile if resource.profile.nil? %>
<%= form_for(resource, :as => resource_name,
:url => registration_path(resource_name)) do |f| %>
<ul>
<%= devise_error_messages! %>
<li class="fullname">
<%= f.fields_for :profile do |profile_fields| %>
<%= profile_fields.label :fullname %>
<%= profile_fields.text_field :fullname %>
<% end %>
</li>
<li class="email">
<%= f.label :email %>
<%= f.email_field :email, :autofocus => true %>
</li>
<li class="password">
<%= f.label :password %>
<%= f.password_field :password %>
</li>
<li class="password">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
</li>
<li>
<%= f.submit %>
</li>
<li>
<p><%= render "devise/shared/links" %></p>
</li>
</ul>
<% end %>
Ответ 2
Для этого вы должны создать свой собственный контроллер регистрации, вот как это сделать:
routes.rb
devise_for :users, controllers: {registrations: 'registrations'}
контроллер
Вы должны заменить :your_fields
полями, которые вы хотите разрешить (извините, если я оставлю это вам, но это делает мой ответ более общим, поэтому можно использовать для всех, кто пройдет)
class RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
allow = [:email, :your_fields, :password, :password_confirmation]
params.require(resource_name).permit(allow)
end
end
Дополнительная информация (вложенные атрибуты + некоторое тестирование)
Также обратите внимание, что если вы используете ассоциацию и accepts_nested_attributes_for
вас будут params
структурированные таким образом
model: {field, field, field, associated_model: {field, field}}
И, конечно же, вы должны использовать ту же структуру в методе sign_up_params
. Если вам нужно это понять, вы можете изменить содержание метода sign_up_params
следующим образом:
def sign_up_params
params.require(resource_name).permit!
end
Это позволит любой параметр, а затем опубликовать форму (она должна пройти на этот раз) и заглянуть в консоль рельсов, чтобы увидеть структуру params
, наконец, вы можете правильно sign_up_params
метод sign_up_params
Проверьте это для получения дополнительной информации http://www.railsexperiments.com/using-strong-parameters-with-nested-forms/
В вашем случае вы должны использовать:
params.require(resource_name).permit( :email, :first_name, :last_name, institutions: [:name], :password, :password_confirmation )
Ответ 3
Использование рельсов 5.1 и разработка 4.4.1 следующая кратчайшая и работает довольно хорошо:
приложение/модели /user.rb
after_initialize do
build_profile if new_record? && profile.blank?
end
приложение/контроллеры/application_controller.rb
before_action :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [{ profile_attributes: :name }])
end
Ключевым моментом здесь является то, что вы можете выполнять следующие действия без создания отдельного контроллера:
- разрешать вложенные атрибуты
- построить отношение для построителя форм