Angular - Rails values not appearing in production - ruby-on-rails

I'm having a strange issue when deploying my app to heroku.
So, there are two ways to create orders. First, whenever a payment is made, an order is automatically created. This is done entirely through Rails. Second, the Orders index view consists of a table which displays all of the orders, with a form to create new orders, which uses Angular. Really, it's more an experiment to practice using Angular.
So, the whole thing works fine in development. All of the orders (created through both methods) show up just fine, along with the corresponding user id, product id, and the total (the amount of money the order would cost).
When I deploy the app, however, I'm having a strange error. Everything works fine, except the totals for orders created with payments aren't showing up. That means, for all orders, the user id as well as product id are showing up, and for orders created with Angular, the order total is showing up. Only for orders created without Angular, the order total isn't appearing.
Some help would be greatly appreciated!!
assets/javascript/angular_app.js
var app = angular.module('shop', ['ngResource']);
app.factory('models', ['$resource', function($resource){
var orders_model = $resource("/orders/:id.json", {id: "#id"});
var products_model = $resource("/products/:id.json", {id: "#id"});
var users_model = $resource("/users/:id.json", {id: "#id"});
var x = {
orders: orders_model,
products: products_model,
users: users_model
};
return x;
}]);
app.controller('OrdersCtrl', ['$scope', 'models', function($scope, models){
$scope.orders = models.orders.query();
$scope.products = models.products.query();
$scope.users = models.users.query();
$scope.addOrder = function(){
order = models.orders.save($scope.newOrder, function(){
recent_order = models.orders.get({id: order.id});
$scope.orders.push(recent_order);
$scope.newOrder = '';
});
}
$scope.deleteOrder = function(order){
models.orders.delete(order);
$scope.orders.splice($scope.orders.indexOf(order), 1);
}
}]);
orders_controller.rb
class OrdersController < ApplicationController
protect_from_forgery
skip_before_action :verify_authenticity_token, if: :json_request?
respond_to :json, :html
def index
#orders = Order.all.to_json(:include => [{:product => {:only => :name}},
{:user => {:only => :email}}])
respond_with #orders
end
def show
#order = Order.find(params[:id]).to_json(:include => [{:product => {:only => :name}},
{:user => {:only => :email}}])
respond_with #order
end
def new
end
def create
#order = Order.create(order_params)
#order.product = Product.find(params[:product_id])
#order.user = User.find(params[:user_id])
OrderMailer.order_confirmation(#order.product, #order.user.email, #order.user.first_name)
respond_with #order
end
def destroy
respond_with Order.destroy(params[:id])
end
protected
def json_request?
request.format.json?
end
private
def order_params
params.require(:order).permit(:product_id, :user_id, :total)
end
end
orders/index.html.erb
<div ng-controller="OrdersCtrl">
<table class="table table-hover">
<thead>
<td>Order ID</td>
<td>Total</td>
<td>Product</td>
<td></td>
</thead>
<tr>
<form ng-submit="addOrder()">
<td>
<span class="form-control" disabled>
<%= Order.last.id + 1 %>
</span>
</td>
<td>
<input type="number" step="0.01" class="form-control" ng-model="newOrder.total">
</td>
<td>
<select ng-model="newOrder.product_id" class="form-control">
<option value="" disabled selected>Select a product</option>
<option ng-repeat="product in products" value="{{product.id}}">{{product.name}}</option>
</select>
</td>
<td>
<select ng-model="newOrder.user_id" class="form-control">
<option value="" disabled selected>Select a user</option>
<option ng-repeat="user in users" value="{{user.id}}">{{user.id}}</option>
</select>
</td>
<td>
<input type="submit" value="+" class="btn btn-success">
</td>
</form>
</tr>
<tr ng-repeat="order in orders | orderBy: '-id':reverse">
<td>
{{order.id}}
</td>
<td>
<strong>{{order.total | currency}}</strong>
</td>
<td>
{{order.product.name}}
</td>
<td>
{{order.user.email}}
</td>
<td>
<button ng-click="deleteOrder(order)" class="btn btn-danger btn-sm"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></button>
</td>
</tr>
</table>
</div>
config/environments/production.rb
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
config.cache_classes = true
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
config.eager_load = true
# Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Enable Rack::Cache to put a simple HTTP cache in front of your application
# Add `rack-cache` to your Gemfile before enabling this.
# For large-scale production use, consider using a caching reverse proxy like
# NGINX, varnish or squid.
#config.action_dispatch.rack_cache = true
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = true
# Asset digests allow you to set far-future HTTP expiration dates on all assets,
# yet still be able to expire them through the digest params.
config.assets.digest = true
# `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
# Use the lowest log level to ensure availability of diagnostic information
# when problems arise.
config.log_level = :debug
# Prepend all log lines with the following tags.
# config.log_tags = [ :subdomain, :uuid ]
# Use a different logger for distributed setups.
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
# Use a different cache store in production.
config.cache_store = :dalli_store,
(ENV["MEMCACHIER_SERVERS"] || "").split(","),
{:username => ENV["MEMCACHIER_USERNAME"],
:passowrd => ENV["MEMCACHIER_PASSWORD"],
:failover => true,
:socket_timeout => 1.5,
:socket_failure_delay => 0.2
}
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.action_controller.asset_host = 'http://assets.example.com'
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
# config.action_mailer.raise_delivery_errors = false
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
config.assets.js_compressor = Uglifier.new(mangle: false)
end

Related

How to display images in a Rails mailer email?

I have an app that sends an email when a user signs up. I've got the emails to send successfully but the images are not getting sent. I'm hosting on Heroku and using Sendgrid to send emails.
Here's my signup_email.html.erb view:
<tr>
<td style="padding: 20px 0; text-align: center">
<img
src="<%= Rails.application.config.action_mailer.default_url_options[:host] %>assets/email/logo.png"
width="200"
height="50"
alt="logo"
border="0"
style="height: auto; background: #dddddd; font-family: sans-serif; font-size: 15px; line-height: 15px; color: #555555;"
/>
</td>
</tr>
This is not an issue where the browser hides images by default because I've tested on various browsers and tried to show images. The image path in the email shows: heroku-root/assets/email/logo.png
Here's the signup user_mailer.rb:
class UserMailer < ActionMailer::Base
default from: "App <welcome#app.com>"
def signup_email(user)
#user = user
mail(:to => user.email, :subject => "Thank you for joining!")
end
end
I've precompiled assets with rake assets:precompile so the logo is stored in public/assets/email directory.
The production.rb setting:
# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = false
# Generate digests for assets URLs
config.assets.digest = true
config.action_mailer.default_url_options = { :host => ENV['DEFAULT_MAILER_HOST'] }
config.action_mailer.delivery_method = :smtp
config.serve_static_assets = true
I've tried using the inline attachment method from the Rails documentation but emails weren't getting sent at all.
class UserMailer < ActionMailer::Base
default from: "App <welcome#app.com>"
def signup_email(user)
#user = user
attachments.inline["logo.png"] = File.read("#{Rails.root}app/assets/email/logo.png")
mail(:to => user.email, :subject => "Thank you for joining!")
end
end
In the view, I call the logo like this:
<%= image_tag(attachments['logo.png'].url) %>
With the method above the emails don't get sent at all and I get the error that it couldn't find the file logo.
You should just be able to use the regular old <%= image_tag("logo.png") %> helpers just like you would use in your views. You may need to set your asset_host so that it includes a full URL for the images in the emails since they aren't displayed in the browser under your domain.
# I believe these should do the trick:
config.action_controller.asset_host = 'http://localhost:3000'
config.action_mailer.asset_host = config.action_controller.asset_host

Rails 5 app cant send sendgrid emails (Cloud 9 and Heroku)

Ive checked many posts about it and still, cant find the solution..i thought that its working in deployment but no, those emails werent sent..i was just getting them in the console.
Ive checked my sendgrid credentials, i added global variables with dotenv so maybe something is wrong with my code..
I also tried that code to send email directly:
require 'sendgrid-ruby'
include SendGrid
from = Email.new(email: 'test#example.com')
to = Email.new(email: 'test#example.com')
subject = 'Sending with SendGrid is Fun'
content = Content.new(type: 'text/plain', value: 'and easy to do anywhere,
even with Ruby')
mail = Mail.new(from, subject, to, content)
sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'])
response = sg.client.mail._('send').post(request_body: mail.to_json)
puts response.status_code
puts response.body
puts response.parsed_body
puts response.headers
with no luck:
puts response.status_code
400
=> nil
2.3.4 :016 > puts response.body
{"errors":[{"message":"Invalid type. Expected: object, given: string.","field":"(root)","help":"http://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/errors.html#-Request-Body-Parameters"}]}
=> nil
puts response.parsed_body
{:errors=>[{:message=>"Invalid type. Expected: object, given: string.", :field=>"(root)", :help=>"http://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/errors.html#-Request-Body-Parameters"}]}
2.3.4 :017 > puts response.headers
{"server"=>["nginx"], "date"=>["Wed, 04 Apr 2018 17:43:43 GMT"], "content-type"=>["application/json"], "content-length"=>["191"], "connection"=>["close"], "access-control-allow-origin"=>["https://sendgrid.api-docs.io"], "access-control-allow-methods"=>["POST"], "access-control-allow-headers"=>["Authorization, Content-Type, On-behalf-of, x-sg-elas-acl"], "access-control-max-age"=>["600"], "x-no-cors-reason"=>["https://sendgrid.com/docs/Classroom/Basics/API/cors.html"]}
=> nil
My friend sent the same code from his computer and its working.. no idea what to do. Im working on Cloud9, maybe thats the problem.. i dont have to much experience in coding so id really appreciate your help guys :)
My production.rb
Rails.application.configure do
ActionMailer::Base.smtp_settings = {
:address => 'smtp.sendgrid.net',
:port => '587',
:authentication => :plain,
:user_name => ENV['SENDGRID_USERNAME'],
:password => ENV['SENDGRID_PASSWORD'],
:domain => 'heroku.com',
:enable_starttls_auto => true
}
# Code is not reloaded between requests.
config.cache_classes = true
config.eager_load = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.default_url_options = { :host =>
'myapp.herokuapp.com', :protocol => 'https'}
# Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Attempt to read encrypted secrets from `config/secrets.yml.enc`.
# Requires an encryption key in `ENV["RAILS_MASTER_KEY"]` or
# `config/secrets.yml.key`.
config.read_encrypted_secrets = true
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
My development.rb
Rails.application.configure do
config.cache_classes = false
# Do not eager load code on boot.
config.eager_load = false
config.action_mailer.delivery_method = :test
config.action_mailer.default_url_options = { :host =>
'https://myapp.c9users.io'}
# Show full error reports.
config.consider_all_requests_local = true
# Enable/disable caching. By default caching is disabled.
if Rails.root.join('tmp/caching-dev.txt').exist?
config.action_controller.perform_caching = true
config.cache_store = :memory_store
config.public_file_server.headers = {
'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}"
}
else
config.action_controller.perform_caching = false
config.cache_store = :null_store
end
Environment.rb
require_relative 'application'
Rails.application.initialize!
ActionMailer::Base.smtp_settings = {
:address => 'smtp.sendgrid.net',
:port => '587',
:authentication => :plain,
:user_name => ENV['SENDGRID_USERNAME'],
:password => ENV['SENDGRID_PASSWORD'],
:domain => 'heroku.com',
:enable_starttls_auto => true
}
The SendGrid API is pretty fragile, and even more so in Rails. You're probably getting that error because you're using Mail instead of SendGrid::Mail. The sample code provided by SendGrid has this flaw, presumably because they tested it in a Ruby script instead of a Rails environment. Mail is already an existing class in Rails, and Rails does this weird thing where everything is automatically imported everywhere, unlike normal Ruby code.
Change the relevant lines to something like this, instead:
mail = SendGrid::Mail.new(from, subject, to, Content.new(type: 'text/plain', value: 'hi this is a test email'))
mail.add_content Content.new(type: 'text/html', value: '<h1>test email</h1><p>hi</p>')
Also note that if you want to send both a plain-text and an HTML body, you have to do it that EXACT order.
If you don't pass any content into the new method, and just call add_content twice, you'll get another one of those nonsense Invalid type. Expected: object, given: string errors, because the constructor will add nil to the list of contents.
If you pass the HTML content into the constructor and call add_content for the plain-text content, you'll get a different error saying that the plain-text content HAS to be added first.
A generally useful thing to do when you're getting these errors is to print out mail.to_json. That will give you a little more insight into what your code is sending to SendGrid.

Rails image_tag not using CDN Assets

I've recently setup a CDN for my application, almost everything works fine, like my static assets, my JS and CSS.
But some object assets (images) keep using my S3 URL to fetch the data from, for example:
<%= image_tag(#listing.cover.url(:large))%>
Becomes, in production:
<img src="https://musicjungle.s3.amazonaws.com/listing_covers/5045/large.jpg?1484594254" class="fotorama__img" style="width: 548px; height: 548px; left: 91px; top: 0px;">
Instead of using my CDN. For the record, here is the piece of my production.rb where I setup the CDN:
#CDN settings
config.action_controller.asset_host = "d1bfllp5zjnl7u.cloudfront.net"
As I described, all my other assets are rendered without problem, but those still use the S3. Maybe this is related to an attachment helper that I have? I created one to upload the images of the application to the S3, here is the code:
module Shared
module AttachmentHelper
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def has_attachment(name, options = {})
# generates a string containing the singular model name and the pluralized attachment name.
# Examples: "user_avatars" or "asset_uploads" or "message_previews"
attachment_owner = self.table_name.singularize
attachment_folder = "#{attachment_owner}_#{name.to_s.pluralize}"
# we want to create a path for the upload that looks like:
# message_previews/00/11/22/001122deadbeef/thumbnail.png
attachment_path = "#{attachment_folder}/:id/:style.:extension"
if Rails.env.production?
options[:path] ||= attachment_path
options[:storage] ||= :s3
options[:s3_credentials] ||= {
:bucket => 'bucket-name',
:access_key_id => 'KEY_ID',
:secret_access_key => 'ACCESS_KEY'
}
options[:s3_permissions] ||= 'private'
options[:s3_protocol] ||= 'https'
options[:s3_headers] ||= {
'Cache-Control' => 'max-age=315576000',
'Expires' => 10.years.from_now.httpdate
}
else
# For local Dev/Test envs, use the default filesystem, but separate the environments
# into different folders, so you can delete test files without breaking dev files.
options[:path] ||= ":rails_root/public/system/attachments/#{Rails.env}/#{attachment_path}"
options[:url] ||= "/system/attachments/#{Rails.env}/#{attachment_path}"
end
# pass things off to paperclip.
has_attached_file name, options
end
end
end
end
Try setting the s3_host_alias option in your Paperclip options:
options[:s3_host_alias] = "d1bfllp5zjnl7u.cloudfront.net"

Rails 4 asset path/url helpers ignore host override option. What am I missing?

I am trying to override the CDN host configured for my app, just for a particular asset but it seems to ignore the option.
module ApplicationHelper
def icon(name, *opts)
content_tag :svg, class: "icon", "aria-hidden" => true do
# Use same origin asset host to avoid cross-origin issues with the <use> element.
url = image_url("icons/entypo.svg##{name.to_s.dasherize}", host: "example.com")
# Expected => https://example.com/assets/icons/entypo-14602e471cad33414596c56d831c5b8cdcec9477829b9eb6d34221faac7bb54d.svg
# Actual => https://cdn.example.com/assets/icons/entypo-14602e471cad33414596c56d831c5b8cdcec9477829b9eb6d34221faac7bb54d.svg
content_tag :use, nil, "xmlns:xlink" => "http://www.w3.org/1999/xlink", "xlink:href" => url
end
end
end
Example::Application.configure do
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
config.asset_host = "example.com"
config.action_controller.asset_host = ENV["AWS_CLOUDFRONT_DOMAIN"] # => cdn.example.com
config.action_mailer.asset_host = ENV["AWS_CLOUDFRONT_DOMAIN"] # => cdn.example.com
end

Mail not actually being sent though my log says it is

Rails 2.3.5
This is on my local.
I have a simple model / view/ controller
#contact.rb
def deliver_contact
ContactMailer.deliver_contact(self)
end
#contacts_controller
def create
#contact = Contact.new(params[:contact])
respond_to do |wants|
if #contact.save
#contact.deliver_contact
#flash[:notice] = 'Contact was successfully created.'
wants.html { redirect_to('/thanks') }
else
wants.html { render :action => "new" }
end
end
The log says its going out.. i can do it in my console and it says its going out. But nothing actually is received in my inbox. What am I missing?
Update
Here is my development.rb:
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => '25',
:domain => "website.com",
:authentication => :login,
:user_name => "snackmail#gmail.com",
:password => "aged-cheese"
}
The Create Log
Processing ContactsController#create (for 127.0.0.1 at 2010-11-28 16:12:49) [POST]
Parameters: {"commit"=>"PUNCH IT, CHEWY!", "action"=>"create", "authenticity_token"=>"3zayXGIOWeNLwb+jhx5cIxWgHqEJdv6iwj6I=", "contact"=>{"name"=>"bob marley", "message"=>"asdfasdf", "state_id"=>"Regarding an existing order", "email"=>"daniel#gmail.com"}, "controller"=>"contacts"}
Cache miss: Spree::Config ({})
Preference Load (0.3ms) SELECT * FROM "preferences" WHERE ("preferences".owner_id = 1 AND "preferences".owner_type = 'Configuration')
Configuration Load (0.1ms) SELECT * FROM "configurations" WHERE ("configurations"."id" = 1)
CACHE (0.0ms) SELECT * FROM "configurations" WHERE ("configurations"."id" = 1)
Cache write (will save 2.65ms): Spree::Config
Contact Create (0.8ms) INSERT INTO "contacts" ("name", "city", "zip", "created_at", "optin", "updated_at", "state_id", "message", "email") VALUES('bob marley', NULL, NULL, '2010-11-28 21:12:49', NULL, '2010-11-28 21:12:49', 'Regarding an existing order', 'asdfasdf', 'daniel.levine4#gmail.com')
Sent mail to daniel#gmail.com
Date: Sun, 28 Nov 2010 16:12:50 -0500
From: info#jersey.com
To: daniel#gmail.com
Subject: HOLY !# you got mail!
Mime-Version: 1.0
Content-Type: text/html; charset=utf-8
<strong>You have just received a dank crispy email.</strong>
<br />
<p>
Here are the details of the message:
</p>
<p>
<strong>Name:</strong>
bob marley
</p>
<p>
<strong>Email:</strong>
daniel#gmail.com
</p>
<p>
<strong>Subject:</strong>
Regarding an existing order
</p>
<p>
<strong>Message:</strong>
<br />
asdfasdf
</p>
Redirected to http://localhost:3000/thanks
Completed in 893ms (DB: 5) | 302 Found [http://localhost/contacts]
update:
Tried using the gmail tls plugin but it didn't work. tried moving the settings around to environment.rb to development.rb .
I am using spree, but if I put something in environment or development.rb in /config it overrides Spree's defaults. Alternatively, I can create the mail server from within Spree's admin, and with the right specs, it still doesn't budge.
If you are running your application in develop mode your email will not be sent but logged. To actually send an email in develop mode change config/environment.rb to something like:
Rails::Initializer.run do |config|
...
config.action_mailer.delivery_method = :sendmail # add this line
end
In config\environments\development.rb do you still have the following lines:
# Don't care if the mailer can't send
config.action_mailer.raise_delivery_errors = false
If so, comment those, and add the following lines
to enable deliveries from development:
# To test if we can actually send mails!
config.action_mailer.raise_delivery_errors = true # for test
config.action_mailer.perform_deliveries = true
I found two items that solved this piece for me.
I was using Spree, so that I meant I had to configure the mail settings internally. Before I realized that I had gone with #lbz's request to install a plugin for TLS in Gmail sendings. It turns out, that that silently conflicted with the settings, so when I uninstalled it, it worked.
To get emails to be sent on your testing server, you must also comment this line :
# config.action_mailer.delivery_method = :test

Resources