Search code examples
ruby-on-railsrubydevisefriendly-idwrite-once

FriendlyID Controller names validates inclusion issue


Basically I have an app(using devise), where a user signs up registrations#new with just an email and password; this registers and creates the user. It immediately takes them to registrations#edit where they enter the rest of their information.

I am using a :name attribute with friendly_id for vanity urls. This attribute has 3 requirements:

  1. It must be written once but unchangeable after it is written.
  2. It can not be any of the controller names (or it will break the app).
  3. It is unique

For #2 So I added the following validation to my model: `

  validates :name, :exclusion => { :in => %w(
  admin cars registrations users
 ), :message => "Sorry \"%{value}\" is taken!"}`

For #3 I added validates_uniqueness_of :name

For #1 I have the following in my view under registrations#edit:

<% if @user.name.blank?%>
                <br>
                <h2>Choose your username</h2>
            
                    <%= f.input :name,  :value => "Username" , required: true, autofocus: true, label:false, class: 'usernameinputc'  %>
           
<br>

This effectively hides it from the user if it doesn't exist. The problem I am having is that if they enter a controller name as their :name or something already taken it will give a devise error, and send them back but the field will be hidden. If i remove the conditional then it allows them to change their :name even if it was valid? How can i make it so it shows only if the name attribute hasn't saved?

Note: I tried if @user.name.persisted? it gave me a no method error for nilClass(I think because :name didn't exist.

UPDATE

So I have tried to add it as a virtual attribute, I have added a field :username to my permitted params as a virtual attribute. Having a little bit of trouble with the getter and setter methods. I tried this:

def username
  self.name if  self.name.persisted?
end

I still get a no method error.


Solution

  • What if you try this? This will validate your name against the black list, but also sets the user.name to blank when this happens. This way your erb will still render correctly.

      validate do |user|
        if %w(admin cars registrations users).include?(user.name)
    
          user.errors[:name] << "Sorry \"" + user.name + "\" is taken!"
          user.name = ""
        end
      end