-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Slug will not be regenerated when owner object is updated #9
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -149,18 +149,65 @@ def slug_source_value | |
self.send(slug_source) | ||
end | ||
|
||
# The slug is not stale if | ||
# 1. the slug is permanent, and slug column has something valid in it | ||
# 2. the slug source value is nil or empty | ||
# 3. scope is not changed | ||
# The slug is stale if | ||
# 1. the slug is new | ||
# 2. the slug is empty/has an invalid value | ||
# 3. a property which affects the slug is dirty | ||
# 4. scope change | ||
def stale_slug? | ||
!( | ||
(permanent_slug? && !slug.blank?) || | ||
slug_source_value.blank? | ||
) || | ||
!(!new? && (dirty_attributes.keys.map(&:name) & | ||
(self.class.slug_options[:scope] || [])).compact.blank? | ||
) | ||
stale = false | ||
if new? | ||
# 1. slug is new | ||
stale = true | ||
end | ||
|
||
if (permanent_slug? && (slug.nil? || slug.empty?)) || | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIRC, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's from active_support. I read somewhere that it's equivalent, but I can change it back to "blank?" for simplicity. If this is the only reason we need active_support, would there be benefit in keeping this line the way it is? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, I wouldn't introduce such a big dep just because of one method. Though, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep. Here's how ActiveSupport defines def blank?
self !~ /[^[:space:]]/
end |
||
(slug_source_value.nil? || slug_source_value.empty?) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This expression seem to be different to the original one. |
||
# 2. Slug is empty and doesn't have a valid value | ||
stale = true | ||
end | ||
|
||
return true if stale == true | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point! Curse my C background. |
||
|
||
if (!permanent_slug? && false == dirty_attributes.keys.map(&:name).empty?) | ||
# 3. Test for staleness. Does our dirty attribute change the slug | ||
# source value? Lets do a test. | ||
dirty_attributes.keys.map(&:name).each do |key| | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whoa, whoa! Hold on a sec here. This is not a good way to do it. You can trigger hell of a side effect by all this assignments. If you really want to check it this way, you better cache There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's also a bug when the attribute is stale because it's nil and dirty. This will claim it's not an important attribute and we won't know the slug has gone stale. Your idea is much better! I'll need to code that up... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you know a good hook which can be used to accomplish what you've described? #initialize might work but I think it would completely break lazy loading on the slug's generation properties. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bumping this line item. @cheba, do you know a solution to the "nil" problem I described, or can you help figure out how to accomplish the solution you suggested? |
||
prev_value = self.slug_source_value | ||
prev_key = self.send(key) | ||
|
||
# Modify the information at :key | ||
self.send "#{key}=", nil | ||
|
||
# Test the slug source value for differences. This might | ||
# outright fail due to us setting the property to nil, so | ||
# lets call it stale when that happens. | ||
begin | ||
if self.slug_source_value != prev_value | ||
stale = true | ||
end | ||
rescue | ||
stale = true | ||
end | ||
|
||
# Restore key to what it was before. | ||
self.send "#{key}=", prev_key | ||
|
||
break if stale == true | ||
|
||
end | ||
|
||
end | ||
|
||
return true if stale == true | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see why you resort to early return in this method. It cuts down unnecessary computation. Though, I really don't like it. You have to read the whole (now huge) method to understand why it returns not what you might expect. I greatly prefer compact logic expession that was here before. It equally cuts down unnecessary computation and really is much more compact. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, the more compact evaluation felt like reading a regular expression to me. Hard to understand the whole thing without understanding how each piece evaluates. It's also really hard to set a breakpoint in the debugger or step through! I prefer the spread-out style with comments next to what each operation represents. My reason is maintainability: adding an additional step to the algorithm or removing one becomes less complicated when each step is chunked by comments. With the old mathematical evaluation, you've gotta interpret each piece of logic and decide where a new one should be inserted! I'm not too worried about extra computation. Computers process any O(1) algorithm quickly! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Unless it's IO-bound. 😉 Anyway, my concern is not that there's extra computation done. You effectively cut it down by early returns. Ruby has implicit return. The last value of the method is what's returned. And most methods do just that. Early return breaks that pattern. That's why I don't like it much. My suggestion. Break it down into smaller private methods and combine them here with logic operators. def stale_slug?
new? ||
empty_slug? || invalid_slug? ||
dirty_source? ||
changed_scope?
end |
||
|
||
unless (dirty_attributes.keys.map(&:name) & | ||
(self.class.slug_options[:scope] || [])).empty? | ||
# 4. Stale due to scope change | ||
stale = true | ||
end | ||
|
||
stale | ||
end | ||
|
||
private | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that this comment adequately reflects the changed logic. Also, inverted logic is hard to evaluate. I'll give it a shot a bit later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I flipped it to positive logic! I'm describing when "true" will be returned, rather than when "false" will be returned. To me this is easier to read, but I'm probably biased.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that listing cases when
true
is returned is better.I'm saying that "the slug is new" doesn't seem to be inverse of "the slug is permanent, and slug column has something valid in it".