Cleaning up your logic a bit yields this:
def process_message(message, subscriber)
case message
when "tulup"
subscriber.update(subscribe: true)
subscriber.add_to_group("visitor")
"You are now subscribed for updates."
when "stem"
subscriber.update(subscribed: false)
subscriber.add_to_group("visitor")
"You have unsubscribed from notifications. Test 'TULIP' to start receiving updates again"
when "dancers"
subscriber.update(subscribed: true)
subscriber.add_to_group("dancers")
"You have been subscribed to the Dancers list"
when "staff"
subscriber.update(subscribed: true)
subscriber.add_to_group("staff")
"You have been subscribed to the Staff list"
when "volunteer"
subscriber.update(subscribed: true)
subscriber.add_to_group("volunteer")
"You have been subscribed to the Volunteer list"
else
# If we don't recognize the command, text back with the list of
# available commands
"Sorry, we don't recognize that command. Available commands are: 'TULIP' or 'STEM'."
end
end
You can see that I transformed your if
expression into a case
. I've also separated "tulip"
and "stem"
cases into separate cases. As far as I could tell the only reason you combined them into one is that they both called subscriber.add_to_group("visitor")
. One line's duplication is easily justified by the improved clarity.
Now we can see where the duplication lies. Each branch in the case
expression does three things: 1. Updates the subscriber's subscribed
attribute according to message
; 2. Adds the subscriber to a group according to message
; and 3. Returns some output according to message
.
I said "according to message
" three times just now to emphasize that in each case we have a mapping from message
to some value: message
to group, message
to subscribed
, and message
to output. I'll come back to subscribed
, but for the other two we see a clear opportunity to use a hash:
COMMAND_TO_GROUP = {
tulip: "visitor",
stem: "visitor",
dancers: "dancers",
staff: "staff",
volunteer: "volunteer"
}.freeze
COMMAND_TO_OUTPUT = {
tulip: "You are now subscribed for updates.",
stem: "You have unsubscribed from notifications. Test 'TULIP' to start receiving updates again",
dancers: "You have been subscribed to the Dancers list",
staff: "You have been subscribed to the Staff list",
volunteer: "You have been subscribed to the Volunteer list"
}.freeze
Now for each message
we can just do a hash lookup to get the appropriate group and output.
As for subscribed
, we only have one false
case ("stem"
), so a hash might be overkill. But it's still good to move that logic into a method:
VALID_COMMANDS = Set.new(%i[ tulip stem dancers staff volunteer ]).freeze
def update_subscribed!(subscriber, command)
raise "Invalid command!" unless VALID_COMMANDS.member?(command)
subscribe = !(command == :stem)
subscriber.update(subscribe: subscribe)
end
Now we have all the pieces we need to refactor the process_message
method:
def process_message(command, subscriber)
command = command.downcase.to_sym
unless VALID_COMMANDS.member?(command)
return "Sorry, we don't recognize that command. Available commands are: " \
"'TULIP' or 'STEM'."
end
update_subscribed!(subscriber, command)
subscriber.add_to_group(COMMAND_TO_GROUP[command])
COMMAND_TO_OUTPUT[command]
end
I've put the complete code at the end of this answer.
A few more important notes:
This shouldn't be in your controller. Logic like this should go in a model or a service object.
A smarter place to put the strings that I've put in the COMMAND_TO_OUTPUT
hash would be in locale files, e.g.:
# config/locales/en.yml
en:
command_response:
tulip: You are now subscribed for updates.
stem:
You have unsubscribed from notifications. Test 'TULIP' to start receiving
updates again.
# ...
Then you could fetch the messages using the I18n API, e.g. I18n.t('command_response.#{command}')
.
Complete code:
VALID_COMMANDS = Set.new(%i[ tulip stem dancers staff volunteer ]).freeze
COMMAND_TO_GROUP = {
tulip: "visitor",
stem: "visitor",
dancers: "dancers",
staff: "staff",
volunteer: "volunteer"
}.freeze
COMMAND_TO_OUTPUT = {
tulip: "You are now subscribed for updates.",
stem: "You have unsubscribed from notifications. Test 'TULIP' to start receiving updates again",
dancers: "You have been subscribed to the Dancers list",
staff: "You have been subscribed to the Staff list",
volunteer: "You have been subscribed to the Volunteer list"
}.freeze
def process_message(command, subscriber)
command = command.downcase.to_sym
unless VALID_COMMANDS.member?(command)
return "Sorry, we don't recognize that command. Available commands are: " \
"'TULIP' or 'STEM'."
end
update_subscribed!(subscriber, command)
subscriber.add_to_group(COMMAND_TO_GROUP[command])
COMMAND_TO_OUTPUT[command]
end
def update_subscribed!(subscriber, command)
raise "Invalid command!" unless VALID_COMMANDS.member?(command)
subscribe = !(command == :stem)
subscriber.update(subscribe: subscribe)
end