In this simplified scenario, I have a model called Post
Each post has a title and a permalink
The permalink is used in the url - i.e. http://mysite.com/blog/permalink
Before a post is created, a callback sets the permalink to be the same as the title
I validate the uniqueness of each title but I do not explicitly validate the uniqueness of the permalink for three reasons:
- the permalink is equal to the title, which has already been validated for uniqueness
- users have no concept of the permalink, since they are never asked to enter one, so when they get an error telling them that the permalink needs to be unique, they don't have a clue what it means
- i'm using mongoid for the ORM and the permalink is the key for each post, and mongoid doesn't seem to let you modify a key
Now imagine the following scenario:
A user creates a post titled "hello" and the url is http://mysite.com/blog/hello
The user changes the title to "goodbye", but the permalink stays the same since it is immutable by design. This is fine, it's what I want and helps to prevents link-rot.
The user then creates a new post, titled "hello" which does not fail the validations since we changed the title of the first post already
The problem here is that we've now got two posts with t开发者_JAVA百科he same url thanks to our before_create callback.
As I said, I don't want to validate the uniqueness of the permalink as the user in the above scanrio, upon creating the second posts would receive the "permalink must be unique" error and I just know this will confuse them
So I was thinking, is there a validation, or a technique that allows me to prevent a user from creating a post which has a title that is equal to an existing permalink?
If all else fails, then I will just validate the uniqueness of the permalink and write out a really lengthy validation error message that details what the permalink is, and why this one is not deemed to be unique
The stuff we have to think about when making webites, what a carry-on
I can think of four possible solutions:
Validate the uniqueness of permalink like this:
validates_uniqueness_of :permalink, :message => "This title is already taken"
This will present the user with an understandable message.
change your
before_create
callback to create a numbered permalinkdef what_ever_your_callback_is_named self.permalink = self.title.permalinkify # or however you create the permalink while self.find_by_permalink(self.permalink) # check if it is an already numbered permalink if self.permalink =~ /^(.*)(-(\d+))?$/ self.permalink = "#{$~[1]}-#{$~[3].to_i++}" else self.permalink << "-2" end end end
change your
before_create
to abefore_save
callback, but than the resulting link is only permanent as long your title doesn't change.use friendly_id for creating and managing the permalink. It's very powerfull.
Your method that creates the permalink name could check whether that permalink is unique and if not then append a YYYYMMDDHHMMSS value (or some other value to create a unique permalink) to the permalink.
You can write a custom validation method
class Post < ActiveRecord::Base
# You'll need to check only when creating a new post, right?
def validate_on_create
# Shows message if there's already a post with that permalink
if Post.first(:conditions => ["permalink = ?", self.title])
errors.add_to_base "Your error message"
end
end
end
精彩评论