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.
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