Search code examples
ruby-on-railsformsdevise

Insert parameters in a Devise controller


I am trying to customize a Devise registrations controller for a context where the user cannot enter an email address as their email has been manually entered previously before they can access the signup page. To achieve this in the UI, I have overridden the new.html.erb template to prefill the email field and to mark it in HTML as disabled:

<%= f.email_field :email, autocomplete: "email", disabled: true %>

I prefill the email in the overridden registrations controller:

def new
  super do |resource|
    resource.email = required_email
  end
end

Unfortunately, in Rails this means that the resulting POST call made when the form is submitted has no email parameter†. That is actually good, as I don't want the user to be able to modify their email in the browser by working around the disabled field or by injecting a different address a different way. The problem is that I need to also insert this email into the resulting params in the create action so that the user object is properly validated.

I have tried overriding the params in the controller:

def signup_params
  super.merge(email: required_email)
end

I have tried also setting the resource attributes the same was as I do in the new action (shown above).

None of these have any result, as I still get a validation error that "Email can't be blank". I have attempted to dive into the Devise source code to inspect how the form params are handled, but it is complicated enough a system that I cannot see any easy hooks or methods to call to modify the process.


† I am aware that this is intended behavior for disabled fields, and I am actually implementing the field as readonly, however I am using disabled here as I also want the ability to, in theory, add the parameter even if there is no field for it in the form.


Solution

  • The answer is to sidestep devise entirely and inject the param at the Rails level:

    def create
      params[:user].merge!(email: required_email)
    
      # Other override code
    end