Many simmilar Q/A on this topic here and there, but I was unable to find exact solution for my problem. Using Rails 3.0.9 now, and trying to upgrade existing older application(not Rails).
The goal is to send simple email to new clients created by admins.
Have been following this oficial guide (and many others), but with no success.
The issue is, that method(s) defined in this controller, from class 'UserMailer', aren`t recognised from another controller, while class 'UserMailer' itself recognised is(how do I know this, will be explained below):
/app/mailers/user_mailer.rb
class UserMailer < ActionMailer::Base
default :from => "info#xxxxx.sk"
def kokotina # << this is just a dummy method for testing
caf = "ssss"
end
def regMailUsr(nazov, priezvisko, email, pass)
#nazov = nazov
#priezvisko = priezvisko
#email = email
#pass = pass
#url = "http://loyalty2.xxxx.sk"
mail(to: email, subject: 'Vaša registrácia bola dokončená.')
end
end
I have also created View for this mail controller but that is not important right now.
The fragments from clients controller are here:
/app/controllers/clients_controller.rb
# encoding: UTF-8
class ClientsController < ApplicationController
load_and_authorize_resource
.......
def new
#noveHeslo = genHeslo(10) # << I defined this in application_controller.rb and it works
UserMailer.kokotina # << just a dummy method from UserMailer
#client = Client.new(params[:client])
.......
end
.......
def create
.......
if #client.save
#send email to new client:
UserMailer.regMailUsr(params[:client][:fname], params[:client][:lname], params[:client][:email], params[:client][:password]).deliver
.....
end ......
Now how do I know that my class is loaded? If in client controller, I change 'UserMailer' to 'xUserMailer', I will get 'no class or method in ...' error, but without 'x', I get only:
'undefined method `kokotina' for UserMailer:Class'
I also tried to define my methods in UserMailer:Class like this:
def self.kokotina # << this is just a dummy method for testing
caf = "ssss"
end
#or even like this
def self <<
def kokotina # << this is just a dummy method for testing
caf = "ssss"
end
end
#and then tried to invoke this method(s) like this:
UserMailer.new.kokotina
#or simply
kokotina
Strange is, that when I put contents of file '/app/mailers/user_mailer.rb' at the end of 'application_helper.rb' file, just after the end of 'module ApplicationHelper', I get no errors but of course, it won`t work.
Please keep in mind that I have no problem coding in another languages, but this mystic/kryptic rules of Ruby on Rails are still a complete mistery to me and unfortunatelly, I don`t have time or even motivation to read time extensive quides or even books for RoR beginners. I have been coding much more difficult applications and implementations, but this heavily discriminating system is driving me nuts.
Thank you all!
Problem solved!
The trick was, that in '/app/mailers/user_mailer.rb', I had multibyte characters. In mail subject.
So I added:
# encoding: UTF-8
at the very first line of '/app/mailers/user_mailer.rb'
I found this by total accident: later my rails app could not start, and server was simply throwing HTTP 500 error. So no trace, error defining etc.
I found out that multibyte string in:
mail(to: email, subject: 'Vaša registrácia bola dokončená.')
Was responsible for crash. When I removed that string, I noticed one important side effect: my methods became magicaly available for another controller!!!!
So if someone could give me at least one reason to lowe Rails...
Related
I am implementing background email processing with Resque using the resque_mailer gem (https://github.com/zapnap/resque_mailer). I was able to get it to work for all my emails except the ones sent by Devise.
I went through a bunch of SO questions, and blog posts (for instance http://teeparham.posterous.com/send-devise-emails-with-resque) but could not find a way to get it to work.
What are the precise steps to follow to get resque_mailer to work with Devise?
I went through tee's answer and several resources online, but couldn't find a working solution.
After a few days of reading through resque-mailer and devise code, a solution that worked for me. Thanks to tee for gist which put me in right direction.
Assuming your app/mailers/application_mailer.rb looks similar to
class ApplicationMailer < ActionMailer::Base
include Resque::Mailer # This will add a `self.perform` class method, which we will overwrite in DeviseResqueMailer
end
In config/initializers/devise.rb
Devise.parent_mailer = "ApplicationMailer"
Devise.setup do |config|
config.mailer = 'DeviseResqueMailer'
end
In the resource class which uses devise, overwrite the send_devise_notification method to send resource class and id instead of object to prevent marshalling
# app/models/user.rb
protected
def send_devise_notification(notification, *args)
# Based on https://github.com/zapnap/resque_mailer/blob/64d2be9687e320de4295c1bd1b645f42bd547743/lib/resque_mailer.rb#L81
# Mailer may completely skip Resque::Mailer in certain cases - and will fail as we write custom handle in DeviseResqueMailer assuming mails are handled via resque
# So in those cases, don't retain original devise_mailer so things work properly
if ActionMailer::Base.perform_deliveries && Resque::Mailer.excluded_environments.exclude?(Rails.env.to_sym)
# Originally devise_mailer.send(notification, self, *args).deliver
# Modified to ensure devise mails are safely sent via resque
resource_id, resource_class = self.id, self.class.name
devise_mailer.send(notification, {resource_id: resource_id, resource_class: resource_class}, *args).deliver
else
super
end
end
Finally, in app/mailers/devise_resque_mailer.rb, fetch the record again from the database and continue
class DeviseResqueMailer < Devise::Mailer
def self.perform(action, *args)
# Hack to prevent RuntimeError - Could not find a valid mapping for admin.attributes
record_hash = args.shift
record = record_hash["resource_class"].constantize.find(record_hash["resource_id"])
args.unshift(record)
super # From resque-mailer
end
end
I feel this approach is a better than using devise-async as all the mails go through same code path. Its easier to control and overwrite if needed.
I'd take a look at devise-async. Looks like it fits your use case. Devise Async
I've got the following model
class User < ActiveRecord::Base
before_create :set_some_values
private
def set_some_values
#do something
end
end
In specs I'm using Fabrication gem to create objects but I can't find a way to stub the set_some_values method. I tried
User.any_instance.stub!(:set_some_values).and_return(nil)
but Fabrication seems to ignore this. Is it possible to do?
This is why I don't like ActiveRecord callbacks -- because if you want to have nothing to do with a callback (because, say, you're making a call to an external service inside the callback) you still have to be concerned about stubbing it out. Yes you could stub out methods inside the callback, but it's the same problem, and actually it's a bit worse because now you are concerned about something inside a method you want nothing to do with.
As usual there are multiple options here.
One option which I've used a lot in the past is, add a condition to your callback that turns it off by default. So your Post class could look like:
class Post
before_save :sync_with_store, :if => :syncing_with_store?
def syncing_with_store?; #syncing_with_store; end
attr_writer :syncing_with_store
def sync_with_store
# make an HTTP request or something
end
end
Now wherever you really want to call the callback (perhaps in your controller or wherever), you can set post.syncing_with_store = true before you call post.save.
The downside to this approach is, it's something that you (and other devs working with you) have to keep in mind, and it's not really obvious that you have to do this. On the other hand, if you forget to do this, nothing bad happens.
Another option is to use a fake class. Say you have a Post that pushes its data to an external data store on save. You could extract the code that does the pushing to a separate class (e.g. Pusher) which would be accessible at Post.pusher_service. By default, though, this would be set to a fake Pusher class that responds to the same interface but does nothing. So like:
class Post
class << self
attr_accessor :pusher_service
end
self.pusher_service = FakePostPusher
before_save :sync_with_store
def sync_with_store
self.class.pusher_service.run(self)
end
end
class FakePostPusher
def self.run(post)
new(post).run
end
def initialize(post)
#post = post
end
def run
# do nothing
end
end
class PostPusher < FakePostPusher
def run
# actually make the HTTP request or whatever
end
end
In your production environment file, you'd set Post.pusher_service = Pusher. In individual tests or test cases, you'd make a subclass of Post -- let(:klass) { Class.new(Post) } -- and set klass.pusher_service = Pusher (that way you don't permanently set it and affect future tests).
The third approach, which I have been experimenting with, is this: simply don't use ActiveRecord callbacks. This is something I picked up from Gary Bernhardt's screencasts (which, by the way, are pretty amazing). Instead, define a service class that wraps the act of creating a post. Something like:
class PostCreator
def self.run(attrs={})
new(attrs).run
end
def initialize(attrs={})
#post = Post.new(attrs)
end
def run
if #post.save
make_http_request
return true
else
return false
end
end
def make_http_request
# ...
end
end
This way PostCreator.run(attrs) is the de facto way of creating a post instead of going through Post. Now to test saves within Post, there's no need to stub out callbacks. If you want to test the PostCreator process, there's no magic going on, you can easily stub out whichever methods you want or test them independently. (You could argue that stubbing out methods here is the same as stubbing out AR callbacks, but I think it's more explicit what's going on.) Obviously this only handles post creation, but you could do the same for post updating too.
Anyway, different ideas, pick your poison.
The #set_some_values method here is called when you call #save on the record. So it has nothing to do with the constructor and therefore you don't need to stub User.any_instance -- just make your record and then do a partial stub, as in:
record.stub(:set_some_values)
record.save
Using Sorcery 0.7.4 with Rails 3.1.1 for authentication.
Everything was going well until I tried to setup password resetting.
Activation works perfectly and emails are sent, but for some reason I get this error when trying to send the reset password email.
undefined method `reset_password_email' for nil:NilClass
I copied the tutorial exactly, and when I did a quick test in the console it shot off the email as expected. In console:
user = User.find(1)
user.deliver_reset_password_instructions!
In the actual controller, it finds the user by the email submitted from the form and in the log I can see it is retrieving the right user and setting the token, but errors out as above and rolls back.
I checked the gem's code for deliver_reset_password_instructions! and there seems to be no reason for it to fail.
PasswordResetsController:
#user = User.find_by_email(params[:email])
#user.deliver_reset_password_instructions! if #user
The following is copied from the gem code:
Instance Method in Gem:
def deliver_reset_password_instructions!
config = sorcery_config
# hammering protection
return false if config.reset_password_time_between_emails && self.send(config.reset_password_email_sent_at_attribute_name) && self.send(config.reset_password_email_sent_at_attribute_name) > config.reset_password_time_between_emails.ago.utc
self.send(:"#{config.reset_password_token_attribute_name}=", TemporaryToken.generate_random_token)
self.send(:"#{config.reset_password_token_expires_at_attribute_name}=", Time.now.in_time_zone + config.reset_password_expiration_period) if config.reset_password_expiration_period
self.send(:"#{config.reset_password_email_sent_at_attribute_name}=", Time.now.in_time_zone)
self.class.transaction do
self.save!(:validate => false)
generic_send_email(:reset_password_email_method_name, :reset_password_mailer)
end
end
The method called above for mailing:
def generic_send_email(method, mailer)
config = sorcery_config
mail = config.send(mailer).send(config.send(method),self)
if defined?(ActionMailer) and config.send(mailer).superclass == ActionMailer::Base
mail.deliver
end
end
Again all the required mailer bits and pieces are there and work from the console.
Uncomment this lines in the sorcery initializer
user.reset_password_mailer = UserMailer
user.reset_password_email_method_name = :reset_password_email
Check your app/mailers/user_mailer.rb file.
If you were following the tutorial you probably did something like copy and paste the method definition from the wiki (which takes one parameter) into the generated method definition (which doesn't take any parameter), hence the 1 for 0 ArgumentError.
In other words, you likely have something that looks like this:
def reset_password_email
def reset_password_email(user)
This is bad, but an easy fix :-)
This is a two part question, but may have the same answer.
Part One:
In our app, one particular controller get hit a lot -- so much so that we'd like to it be logged in a file separate from all other requests. Setting the FoosController.logger is not what I'm looking for, because the request exercises some lib files and active record object that have their logger object, and rails will log some info before handing control to the controller in question.
Part Two:
We have a global before filter included in our root application_controller.rb that is run before most actions of most controllers. This before_filter is very wordy in the logs, and is a candidate for having all its logging info sent to a separate file. This before filter also calls out to libs and ActiveRecord code with their own refererences to the logger.
One possible solution is to run the single controller as its own standalone application. I haven't tried it yet, because it's pretty tied into the internals of app. This approach also would not help with the before_filter.
Are there any good solutions for more fine-grained logging in rails apps?
Thanks!
For part I
I recommend creating your own logger class (possibly inheriting from the ruby logger (1), have the logger filter out the request url and based on that log to a specific file.
For part II
the easiest solution would be to just use a seperate logger for these methods. Instead of logger.debug "your message" you just call method_logger.debug "your message".
Creating your own logger is simple, just use the ruby logger class (1). The following code creates a logger that logs to a my_method.log file in the logs dir of your rails application.
method_logger = Logger.new(Rails.root.join('logs','my_method.log')
You can then write to your log with the following command, which should look familiar to you as rails uses the Ruby logger as well.
method_logger.debug "your debug message here"
(1) http://www.ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html
Here's the code for a custom logger that you can use to solve Part I. I adapted it for my own use from another Stack Overflow question, even including the answerer's inline comments. The main difference is that you can specify a different log path for development and production:
# app/concerns/event_notifications_logger.rb
class EventNotificationsLogger < Rails::Rack::Logger
def initialize(app, opts = {})
#default_logger = Rails.logger
#notifications_logger = Logger.new(notifications_log_path)
#notifications_logger.formatter = LogFormat.new
#notifications_logger.level = #default_logger.level
#app = app
#opts = opts
end
def call(env)
logger = if env['PATH_INFO'] == '/event_notifications/deliver'
#notifications_logger
else
#default_logger
end
# What?! Why are these all separate?
ActiveRecord::Base.logger = logger
ActionController::Base.logger = logger
Rails.logger = logger
# The Rails::Rack::Logger class is responsible for logging the
# 'starting GET blah blah' log line. We need to call super here (as opposed
# to #app.call) to make sure that line gets output. However, the
# ActiveSupport::LogSubscriber class (which Rails::Rack::Logger inherits
# from) caches the logger, so we have to override that too
#logger = logger
super
end
private
def notifications_log_path
Rails.env.production? ? '/var/log/event-notifications.log' : Rails.root.join('log/event-notifications.log')
end
end
Then include it in your application configuration:
require File.expand_path('../boot', __FILE__)
require 'rails/all'
require File.expand_path('../../app/concerns/event_notifications_logger', __FILE__)
module YourApp
class Application < Rails::Application
config.middleware.swap Rails::Rack::Logger, EventNotificationsLogger
# ...
end
end
Rails 3.2 provides filter options for the logs, called "Tagged Logging".
See the announcement or the new Rails 3.2 guide on ActiveSupport.
I'm struggling to get my app to display a timeline of feeds from my app. So far I've used the oauth-plugin, oauth and twitter gems (for rails3) to get it authorised. This has worked just fine.
Now I'm struggling when I try and connect.
I end up with an error:
uninitialized constant Twitter::OAuth
Have checked I don't have another action calling twitter (as in another post here). But so far, no luck.
Hope someone can help!
Edit -
I forgot to mention I'm using Devise to authenticate my users. Have tried inserting:
require 'twitter'
But still no success..
-- EDIT TWO --
Found a solution on the twitter gem git site about depreciating this in version 1.0.
I've now replaced the code in my twitter_token.rb file with:
def client
unless #client
#twitter_oauth=Twitter::Client.new(:TwitterToken.consumer.key,:TwitterToken.consumer.secret)
#twitter_oauth.authorize_from_access(token,secret)
#client=Twitter::Base.new(#twitter_oauth)
end
Which gets rid of that error but now leads to another :(
undefined method `consumer' for :TwitterToken:Symbol
I have also tried this:
def client
unless #client
#twitter_oauth=Twitter::Client.new(:oauth_token =>'TwitterToken.consumer.key', :oauth_token_secret=>'TwitterToken.consumer.secret')
#twitter_oauth.authorize_from_access token,secret
#client=Twitter::Base.new(#twitter_oauth)
end
Which gives the following error:
undefined method `authorize_from_access' for #<Twitter::Client:0x00000102da1530>
Any ideas? I'm going insane!
I'm going to answer my own question here - if it helps one person, it's worth it considering I lost three days to it.
Using the latest twitter gem, devise and oauth-plugin. I was seeing a lot of errors. The latest twitter_token controller on the oauth-plugin site does not work, even though it's been updated for a recent twitter gem..
In the end, I deleted my entire twitter_token.rb file and started again:
require 'twitter'
class TwitterToken < ConsumerToken
TWITTER_SETTINGS={:site=>"http://api.twitter.com", :request_endpoint => 'http://api.twitter.com',}
def self.consumer
#consumer||=OAuth::Consumer.new credentials[:key],credentials[:secret],TWITTER_SETTINGS
end
def client
Twitter.configure do |config|
config.consumer_key = TwitterToken.consumer.key
config.consumer_secret = TwitterToken.consumer.secret
config.oauth_token = token
config.oauth_token_secret = secret
end
#client ||= Twitter::Client.new
end
end
You can then update twitter using something like this:
<%= current_user.twitter_token.client.update("At last it's working!") %>
Also, make sure you're using the rails3 branch of the oauth-plugin..