Spree Confirmation Emails - ruby-on-rails

So, I want to set up my Spree store such that confirmation emails are not sent when we create orders in the back-end, since we get customers who place orders outside of our store website, which we would like entered into our Spree database nonetheless. The best way we can think of to do this (if you have another way, by all means chime in) is to disrupt this bit of code in the orders model (you can find it at /core/app/models/spree/order.rb):
def finalize!
# lock all adjustments (coupon promotions, etc.)
all_adjustments.each{|a| a.close}
# update payment and shipment(s) states, and save
updater.update_payment_state
shipments.each do |shipment|
shipment.update!(self)
shipment.finalize!
end
updater.update_shipment_state
save!
updater.run_hooks
touch :completed_at
if paid? #THIS CONDITIONAL IS THE BIT WE ADDED
deliver_order_confirmation_email unless confirmation_delivered?
end
consider_risk
end
Now it's just a matter of testing this. The only kind of payment that can be tested through the GUI is check, and I need to see if this trips with a credit card payment that's been authorized/not authorized/captured/not captured (since Spree's documentation on what qualifies as a payment_state of 'balance_due', 'pending' or 'paid' is pretttty bad). So I've been trying to use factory girl's stuff to make an order like that, and see whether or not a confirmation email has been sent. The only thing I can find for testing confirmation emails, however, involves sending one out, and also I can't find anything that would help me build a factory for an order that specific. Am I missing something?

Related

Rails 5 - Best way to prevent emails from being sent to unsubscribed users

I am using Rails 5.
I have an Affiliate model, with a boolean attribute email_notifications_on.
I am building a quite robust email drip system for affiliates and can't figure out where the best place is to check if the affiliate has email notifications on before delivering the email.
Most of my emails are being sent from Resque BG jobs, a few others from controllers.
Here is an example of how I am checking the subscribe status from a BG job:
class NewAffiliateLinkEmailer
#queue = :email_queue
def self.perform(aff_id)
affiliate = Affiliate.find(aff_id)
if affiliate.email_notifications_on?
AffiliateMailer.send_links(affiliate).deliver_now
end
end
end
It seems like writing if affiliate.email_notifications_on? in 10+ areas is not the right way to do this, especially if I need another condition to be met in the future. Or is this fine?
I thought maybe some sort of callback in the AffiliteMailer would work, but saw many people advising against business logic in the Mailer.
Any thoughts/advice would be appreciated.
To be honest, I don't think any better way than creating a method in Affiliate model as follows,
def should_send_email?
# all business logic come here
# to start with you will just have following
# email_notifications_on?
# later you can add `&&` or any business logic for more conditions
end
You can use this method instead of the attribute. It is more re-usable and extendable. You will still have to use the method in every call. If you like single liners then you can use lambda.

Rails: Cucumber and Application Controller Methods

I am doing integration testing using Cucumber. In my ApplicationController, I have a method called current_user that provides the current user object. I use this object to add items to a redis database:
$redis.sadd("cart#current_user.id}", [1,5,2])
In my Cucumber steps I test this functionality:
Then /^the redis database should have "(.+)" item ids/ do |count|
expect($redis.smembers("cart#{current_user.id}").count).to eq count.to_i
end
However, it is my understanding that Cucumber does not have access to controller methods, even if they are under ApplicationController, and therefore I cannot user the current_user method the way I would in my controllers.
What I am doing now is since I am testing features, there is only one user in the database so the current_user.id will always be 1, but if I start adding more users this may not work nicely.
Is there a workaround for this?
Your not really using Cucumber as intended here. What you are doing is testing how your application currently works, but really Cukes is best used to specify what your application does and why its important.
Applying more appropriate usage to your current problem leads to the following questions
What is the reason for storing the ids in Redis?
What benefit does the customer get by having these id's stored?
Taking a wild guess you might be saving a basket so that if the user logs out, their basket would still be populated when they come back. Then your scenario would be something like
Scenario: Remember products in basket
Given I am registered
And I am logged in
When I put some products in my basket
And I log out
And I log in again
Then my basket should still have some products in it
Notice how the scenario is all about WHAT you are doing and WHY its important but reveals nothing about HOW this is going to be done. This is a really good way to critique scenarios. Scenarios that contain HOW stuff are going to be harder to write and much harder to maintain. Anyhow enough of that :)
Now you can use standard cucumber stuff like assigned the user to a variable in one step e.g. #i = create_registered_user and then using that user in the other steps e.g. login as: #i
Note that we don't look at the database, only at what the user sees, and we don't reveal anything about HOW this functionality works in the scenario.
If you want to write tests (rather than scenarios) that do reveal how functionality works and do look at databases for results then I'd suggest that rspec would be better suited for this.
do you have a step to login? if so, you can change it a little so you can control which user logs in:
Given "john_doe" logs in to the app
Then you can search by username and do the login in your step. You can do the same on this step:
Then /^the redis database should have "(.+)" item ids/ do |count|
something like
Then /^the redis database should have "(.+)" item ids for user "(.*)"/ do |count, user_name|
user = User.find_by(username: user_name)
expect($redis.smembers("cart#{user.id}").count).to eq count.to_i
end

Use model callbacks or observers for implementing activity feed?

I'm implementing an activity feed for a client similar to Twitter's (it's only activity that pertains to the current signed in user -- i.e. who favorite his/her post, mentions, etc..).. It won't rely on 'push' but instead, the user will have to refresh the page in order to see new activity (for now).
I've been googling & searching around SO for the past hour to find the best way to implement this, and observers keep coming up in the solutions. I also notice that many of these are using push notification. I noticed the approach R Bates took in his public activity railscast btw, which is why I'm asking this question.
What if I don't want to use push notification, would callbacks be ok or even better? Do you think I would still need to use implement other things outside rails for scalability? (like how you may use "Pushapp" for push notifications)
Any suggestions on better solutions or light shed would be helpful.
This is for #gg_s
I'm assuming in this case you're saying I have an activity_feed table (receiver_id, sender_id, activity_type, & activity_id) (belongs to user, belongs_to activity_type (???), :polymorphic => true)
# application_controller.rb
def publish_to_user_feed(message)
current_user.activity_feed << message
end
# favorites_controller.rb
def create
# blah blah blah
publish_to_user_feed "This just happened."
end
In the the favorites_controller's 'create' action, "This just happened" could == "#favorite.user just favorited #favorite.post by #favorite.post.user"
Again, I hope I'm not being too pesky & am pretty sure what I'm asking is obvious, but I think this will help clear things up for me & also help future visitors.
Thanks again
For anyone that wants to know, I'm still working on this.. Just took a little break.. My main concern is how heavy it'll be on the db & other performance issues so if anyone wants to better this (using the code above), feel free :)
Solution: I don't want to overcomplicate things so I'm taking ap's advice.
Use neither.
Callbacks and observers are more complex in this case than you might think. The only automation they provide is the ability to be triggered upon model events. That's it. You are responsible to implement logic determining:
what just happened?
should it be reported?
what to report?
Extending this logic to support several types of activities is needlessly complex. Ditch the automation and publish activities from the controller as they happen on an as-needed basis.
Create a helper method to keep things DRY:
# application_controller.rb
def publish_to_user_feed(message)
current_user.activity_feed << message
end
Then manually post to a user's feed when and where necessary:
# some_controller.rb
def some_action
# perform some action
publish_to_user_feed "This just happened."
end
Reporting directly from the controller is clear, readable, DRY, maintainable, and adhere's to Rails' MVC pattern. No complex callback chains or observers to write.
As a bonus, it is trivial to perform activities without posting to activity feeds, e.g. administrative activity or user privacy settings.

rails 3.1: Where to filter out email addresses that have opted out

Trying to figure out the cleanest way prevent sending email to users who have opted out from receiving them in rails 3.1.
I was thinking about overriding Mail.deliver to check the db and determine if the recipients are unsubscribed or not, then conditionally delivering the email.
That seems like the least intrusive way to go about it, but requires creating the Mail objects that are never going to be sent.
Seems like the most resource conscious way would be to do the check in the controller, thus preventing the Mail objects that are never going to be sent from the burden of existence.
This though seems more intrusive and prone to developers forgetting to make the check when creating new mailers.
Is there a standard practice for this situation?
** edit **
This is for managing a collection of users who have opted out of receiving notifications, rather than something like managing subscriptions to a news letter.
If the attribute that determines whether or not to get email notifications is just a field on a model in the DB, you could create a named scope called something like 'want_email_notifications' to get all the users that have subscribed.
So, if you have a User class, and that class has an attribute called opt_out, then you could do something like:
class User < ActiveRecord::Base
named_scope :want_email_notifications, :conditions => ['opt_out = ?', false]
...
end
Then, to call it, you do User.want_email_notifications, which gives you an array of all User objects that want email notifications.
Then, when you're checking whether or not a given user should receive an email notification, write a condition similar to:
send_email_notification(user_in_question) if User.want_email_notifications.include?(user_in_question)
In this example, send_email_notification is the method where you would call the associated delivery method, which actually sends the email.

Braintree "shopping cart"-like implementation in rails app / finding previous params[:id]?

I'm trying to integrate Braintree into my rails app which already has a deposits controller, model, and view. Right now basically you can specify an amount but I have its status set to "Pending". I would like it so that the user can make such a deposit but then pay for it at any time using Braintree (ala shopping cart). Would I have to create another controller and/or model to do this? (For example all the Braintree examples I've seen want the payment immediately).
Specifically, I've been trying to just work with the 'deposits' I already have. I put the form for the user's name, credit card info, etc. on the deposits "show" page and a confirm button. This seems to work fine if all fields satisfy validation, however it doesn't when there is an error and renders the show page again.
In DepositsController.rb:
def confirm
#deposit = Deposit.find(params[:id])
#result = Braintree::TransparentRedirect.confirm(request.query_string)
if #result.success?
render :action => "confirm"
else
render :action => "show"
end
end
The problem is that :id now is the Braintree transaction ID, rather than the deposits id (primary key). So of course Deposit.find(params[:id]) can't be found.
What is the best way to implement this? Should I store the previous id somehow or get it another way? Should I be using another controller? Thanks!
Short answer is you should be using a Cart model, connected to this Deposit model from what i can gather here. Based on other questions, however, that feeling could change.
So, solely based on what you wrote above:
If we follow a RESTful approach, you should be creating a Deposit#new for all new deposits.
In your Deposit#create, you would then put all of your logic into the deposit.rb model file. this logic includes, going to Braintree and such.
You say you are working with the deposits you already have, in that case, they should be handled in the Deposit#edit method.
Further questions I would ask of you in this regard, are you using ActiveMerchant? If not, why not?

Resources