Reputation: 59232
In my model User
, there already exists an id
column which is auto-incremented. Now I plan to have a unique name for the user.
Now, the user won't be asked for it in the sign up process, so by default, I would like the column to return "user" + id
when called like
user.profile_name #=> should return "user#{user.id}" if nil
I don't want to duplicate the data, so I would want to keep the field nil
until the user enters one.
So, I thought of creating a custom function(or overriding the profile_name
if possible)
# model User.rb
def get_identifier
profile_name ? profile_name : "user#{id}"
end
And using where
to find the user
id, user = params[:identifier], nil
if id[0..3] == "user"
user = User.find_by_id(id[3..-1].to_num)
else
user = User.find_by profile_name: id
But this seems not to be a rails way. I would have to take care of both the cases even when querying.
Is there any way to simplify this in Rails that I'm missing? Else can the current approach be bettered (apart from refactoring the code into methods)?
P.S The question is tagged appropriately with the versions I'm using. Ruby version - 2.1.5
Upvotes: 0
Views: 59
Reputation: 106802
I would argue that you need to backfill profile_name
s for existing users. Otherwise you might run into all kinds of interesting problems.
For example: There are the existing users 1
and 2
, both do not have a unique username yet. User 1
has the profile_name
user1
, analog for user 2
which has user2
as the profile_name
user2
. Now user 1
decides to set a profile_name
and he sets its profile_name
to user2
, what is a unique profile_name
at the moment - at least from a Rails validator's point of view.
To avoid this problems: Always set a unique profile_name
and backfill profile_name
s for existing users.
Upvotes: 0
Reputation: 189
I'd like to preface with this answer with my opinion that your hesitation to "duplicate the data", where the data is really just the id, might be uncalled for. It's not user-editable or anything, so I'm not sure what the downsides are if you're not counting bytes in your database size.
Given the constraints of the question, I'd look at an implementation like this:
class User
def self.find_by_profile_name(profile_name)
where(profile_name: profile_name).first || find_by_default_profile_name(profile_name)
end
def self.find_by_default_profile_name(profile_name)
where(id: DefaultProfileName.from_profile_name(profile_name).id)
end
end
class DefaultProfileName
attr_accessor :id
def self.from_profile_name(profile_name)
new(profile_name.sub('user', ''))
end
def initialize(id)
self.id = id
end
def to_s
"user#{id}"
end
end
I'm sure this could be improved on, but the main takeaway is that encapsulating your default profile name functionality in its own class enables making this bit of functionality contained and more manageable.
Upvotes: 1