13

Tôi đang làm việc trên một ứng dụng web bằng Devise and Rails 4. Tôi có một mô hình Người dùng mà tôi đã mở rộng với 2 trường biểu mẫu bổ sung sao cho khi người dùng đăng ký, anh ấy cũng có thể gửi/họ. (dựa trên http://blog.12spokes.com/web-design-development/adding-custom-fields-to-your-devise-user-model-in-rails-4/). Bây giờ tôi muốn thêm một mô hình Tổ chức giáo dục. Mô hình này has_many: người dùng và người dùng thuộc về: cơ quan. Tôi muốn có thể đăng ký tên tổ chức tên trên cùng một biểu mẫu tôi đăng ký người dùng. Tôi biết tôi cần một nested_attribute trong mô hình Institution của mình, vì đây là phụ huynh, mà tôi sẽ hiển thị trong một chút. Khi tôi cố gắng đăng ký người dùng tôi nhận được trong bảng điều khiển: Thông số không được xác minh: Các tổ chức.Rails 4.0 với Devise. Thuộc tính lồng nhau Các tham số không được chấp nhận

Gợi ý của tôi là tôi không thể cập nhật lớp cha mẹ (Tổ chức) dựa trên lớp con của tôi (Người dùng). Có thể có một giải pháp cho điều này? Hay có ai có kinh nghiệm gì đó tương tự?

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 

đăng ký/new.html.erb Ở đây tôi có các hình thức lồng nhau

<%= 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 %> 

Dựa trên hướng dẫn, tôi đã liên kết trước đó, tôi đã tạo ra một tài khoản mới :: ParameterSanitizer mà kế thừa từ Devise :: ParameterSanitizer và ghi đè phương thức sign_up như sau:

lib/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 

Cuối cùng, application_controller.rb tôi

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 

Cảm ơn bạn đã đọc!

điều khiển params đầu ra:

{"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"} 

EDIT

Như đã đề cập, tôi đã thêm

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)* 

NHƯNG, nếu tôi chỉnh sửa lại để

params.require(resource_name).permit(:email, :first_name, :last_name, :password, :password_confirmation, institution: [:name]) 

Tôi không nhận được lỗi cú pháp nhưng tôi nhận được thông số không được phép: Các tổ chức trong Yêu cầu.

Niềm tin của tôi là điều này xảy ra vì Người dùng là con của Học viện. Tôi có, tuy nhiên, không thể tìm thấy một công việc xung quanh này.

Trả lời

33

config/routes.rb

Tạo điều khiển của riêng bạn đăng ký như vậy ... (see Devise documentation for the details of overriding controllers here ...) ... đó là cách thanh lịch hơn như trái ngược với làm việc đó thông qua ApplicationController

devise_for :users, controllers: {registrations: 'users/registrations'} 

app/controllers/người dùng/registrations_controller.rb

Override phương pháp mới để cre ăn một Profile gắn liền với User mô hình như sau ... chạy phương pháp configure_permitted_parameters trước để khử trùng các thông số (lưu ý làm thế nào để thêm các thông số lồng nhau)

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 

db/di chuyển/xxxxxxxxxxxxxx_create_profiles.rb

Đây là di chuyển tạo mô hình Profile (lưu ý tham chiếu đến User) ... tiểu sử mẫu này chỉ giữ fullname làm e xtension của User nhưng cảm thấy tự do để thêm như bạn muốn!

class CreateProfiles < ActiveRecord::Migration 
    def change 
    create_table :profiles do |t| 
     t.references :user 
     t.string :fullname 
     t.timestamps 
    end 
    end 
end 

app/models/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 

app/models/profile.rb

class Profile < ActiveRecord::Base 

    # Associations 
    belongs_to :user 

    # Validations 
    validates :fullname, presence: true 
end 

app/views/đưa ra/đăng ký/mới. 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 %> 
+5

Câu trả lời tuyệt vời –

+1

Cảm ơn nhiều King'ori, đây là chính xác những gì tôi đang tìm kiếm!Đã tiết kiệm cho tôi thêm một vài giờ thất vọng. – DerProgrammer

+0

@ king'ori Maina Tôi đang sử dụng đá quý devise_auth_token và sau khi rơi trên phương pháp cho cùng một gem Tôi vẫn nhận được tham số Unpermitted: lỗi tài khoản trong nhật ký máy chủ của tôi – Anjan

13

Bạn phải tạo điều khiển đăng ký của riêng bạn để làm như vậy, đây là cách:

tuyến đường.rb

devise_for :users, controllers: {registrations: 'registrations'} 

khiển

Bạn phải thay thế :your_fields bởi các trường bạn muốn cho phép (xin lỗi nếu tôi rời khỏi đó với bạn, nhưng điều đó làm cho câu trả lời của tôi tổng quát hơn, do đó có thể sử dụng cho bất kỳ ai đi qua)

class RegistrationsController < Devise::RegistrationsController 

    private 

    def sign_up_params 
     allow = [:email, :your_fields, :password, :password_confirmation] 
     params.require(resource_name).permit(allow) 
    end 

end 

Thông tin bổ sung (thuộc tính lồng nhau + một số thử nghiệm)

Cũng lưu ý rằng nếu bạn đang sử dụng liên kết và accepts_nested_attributes_for bạn sẽ có params có cấu trúc như thế này

model: {field, field, field, associated_model: {field, field}}

Và tắt tất nhiên bạn phải sử dụng cùng cấu trúc trong phương pháp sign_up_params của bạn. Nếu bạn cần phải hiểu được điều này, bạn có thể thay đổi nội dung của sign_up_params phương pháp như thế này:

def sign_up_params 
     params.require(resource_name).permit! 
    end 

Điều đó sẽ cho phép bất kỳ param, sau đó gửi mẫu của bạn (nó phải vượt qua thời gian này) và nhìn vào đường ray giao diện điều khiển của bạn để xem cấu trúc của params, cuối cùng bạn có thể thiết lập một cách chính xác phương pháp sign_up_params

Kiểm tra này để biết thêm http://www.railsexperiments.com/using-strong-parameters-with-nested-forms/

trong trường hợp của bạn, bạn nên sử dụng:

params.require(resource_name).permit(:email, :first_name, :last_name, institutions: [:name], :password, :password_confirmation)

+0

Thx bạn đã trả lời. Tôi đã thử điều này. Tôi không làm việc vì nó vẫn không cho phép các tham số của mô hình Institution. –

+0

Ok đã sửa câu trả lời của tôi – Benj

+0

Tôi thấy rằng^_ ^. Tôi đã viết nó theo cách sau: allow = [: email,: first_name,: last_name,: password,: password_confirmation,: name], trong đó: name là một trường trong mô hình khác. –

2

Sử dụng đường ray 5.1 và đưa ra 4.4.1 Sau đây là ngắn nhất và hoạt động khá tốt:

app/models/user.rb

after_initialize do 
    build_profile if new_record? && profile.blank? 
end 

app/controllers/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 

Chìa khóa ở đây là bạn có thể làm theo mà không cần tạo con riêng troller:

  • giấy phép lồng nhau thuộc tính
  • xây dựng mối quan hệ đối với hình thức xây dựng