rails 3 access to model and mailer from external script - ruby

As in topic how i can access model and mailer from ruby script? I want to do some thinks which are not web related and can't be done via rails but are bound to database used in rails. For eg. i want to check when sb premium ends and 7 days before sand him email.
Best regards

Set up a rake task which you can call and check the output of.
In lib/tasks/appname.rake
task :do_some_stuff => :environment do
# any code you want in here.
puts "some output"
end
You can then call it from the command line with
rake do_some_stuff

Related

Models on the Rails Console

I have created a simple class under the models folder like so:
class CaffeineShops
def initialize
end
end
When I run rails console and try CaffeineShops.new(), I get a message: "NoMethodError: undefined method 'new' for CaffeineShops::Module"
I am using Rails 4.1.
Any ideas why I am getting that error?
You cannot name a model the same name as the application itself. When you run rails g caffeine_shops this creates a module named CaffeineShops which will power your application.
The module is utilized in many files including
config\application.rb
config\environment.rb
config\environments\development.rb
config\environments\production.rb
config\environments\test.rb
config\initializers\secret_token.rb
config\initializers\session_store.rb
config\routes.rb
config.ru *actually starts the application on Rack-based servers
Rakefile *loads rake tasks for the application
When you then try to name a class the same name it creates ambiguity in the rails application so your code is assuming you mean the module CaffeineShops not the class CaffeineShops.
If you were to actually use a generator to define this model rails would make it very clear there was a problem with this e.g.
rails g caffeine_shops
cd caffeine_shops
rails g model caffeine_shops
#=>The name 'CaffeineShops' is either already used in your application or reserved
by Ruby on Rails. Please choose an alternative and run this generator again.

Padrino send errors automatically via email

Can anyone suggest a way to have any application errors in a Padrino app send these errors via email?
I already have the Padrino Mailer configured properly and can send test emails, I just have no idea how to configure the app to send me a report via mail (as well as logging it, of course) whenever an error occurs.
Thanks.
I ended up using the padrino-contrib gem. With it, you can install the plugin you need (of course you can do it manually also):
padrino-gen plugin exception_notifier
Which will add it to your gem file and also edit your app/app.rb and boot.rb files to load this gem.
Then in app/app.rb you put something like:
register Padrino::Contrib::ExceptionNotifier
set :exceptions_from, "noreply#domain.com"
set :exceptions_to, "your_address.domain.com"
And that's it.
The nice thing about letting the plugin install it for you is that if you're more familiar with Rails than Padrino (as is my case) this will not only set things up for you, but also show you were the directives need to go.
Hope this helps someone else.
A good approach should be using exception handlers. Adding a begin..rescue block to your code, and if there is an exception, you send the email and continue to the desired behavior.
def some_action
begin
# some code that could go wrong
rescue SomeExceptionClass => some_variable
# here you send the email with the errors
# render stuff, redirect stuff, etc
end
end

Heroku and Web scraping

I have a nokigiri web scraper that publishes to a database that I'm trying to publish to heroku. I have a sinatra application frontend that I want to have pull in from the database. I'm new to Heroku and web development, and don't know the best way to handle something like this.
Do I have to place the web scraper script that uploads to the database under a sinatra route (like mywebsite.com/scraper ) and just make it so obscure that no one visits it? In the end, I'd like to have the sinatra part be a rest api that pulls from the database.
Thanks for all input
There are two approaches you can take.
The first one is to use One-off dynos by running the scraper through the console using heroku run YOURCMD. Just make sure scraper don't write to disk but uses database.
More information:
https://devcenter.heroku.com/articles/one-off-dynos
The second is differentiating between scraper and web process in a way that you have web process for normal UI interaction and a scraper process which web process can spawn/talk to. If you take this route it's up to you how to protect it from rest of the world (auth/url obfuscation etc.).
More information:
https://devcenter.heroku.com/articles/background-jobs-queueing
I did it by creating a rake task and using the one-off dynos as mentioned by XLII
Here is my rake task file
require 'bundler/setup'
Bundler.require
desc "Scrape Site"
task :scrape, [:companyname] => :environment do |t, args|
puts "Company Name is :" + args[:companyname]
agent = Mechanize.new
agent.user_agent_alias = 'Mac Safari'
puts "Agent (Mac Safari Created)"
# MORE SCRAPING CODE
end
You can simply run it by call
heroku run rake scrape[google]

What is the correct way to setup database with DataMapper and Sinatra on production server?

From the DataMapper document, I think there are at least four functions need to be called to have database setup:
DataMapper.setup(:default, 'sqlite:///path/to/project.db')
DataMapper.finalize
DataMapper.auto_migrate!
DataMapper.auto_upgrade!
In many DataMapper+Sinatra tutorials I learned that auto_migrate! and auto_upgrade! are not supposed to be called every time the app is loaded on production server. But in the meanwhile many examples call these functions in the main ruby file of the sinatra app, say app.rb, without additional check. And some examples do not call finalize at all. So far I am confused and I am not sure what to do on the production server.
Take this following simple app.rb for example, I have some questions:
Where and when should finalize be called?
When deploying the app first time there is no db file on the production server, how do I have it automatically created? Or do I have to create the project.db file manually?
Since the auto_upgrade! is wrapped in :development block, it won't be called on production server. How am I supposed to upgrade database when I add or remove columns in it?
require 'sinatra'
require 'data_mapper'
configure do
DataMapper.setup :default, "sqlite3://#{Dir.pwd}/project.db"
end
class Book
include DataMapper::Resource
property :id, Serial
property :title, Text
belongs_to :author
end
class Author
include DataMapper::Resource
property :id, Serial
property :name, Text
has n, :books
end
configure :development do
DataMapper.auto_upgrade!
end
get '/:id' do
#author = Author.get params[:id]
erb :list_author_and_his_books # The template has nothing to do with this question, ignore it
end
get '/new' do
# Some code for user to input book or author details
end
get '/create' do
# Some code to create book or author in db
end
Thanks for reading this long post :D
Where and when should finalize be called?
From http://rdoc.info/github/datamapper/dm-core/DataMapper#finalize-class_method
This method should be called after loading all models and plugins.
When deploying the app first time there is no db file on the production server, how do I have it automatically created? Or do I have to create the project.db file manually?
It depends on your hosting arrangement, but the main thing to do is put the running of migrations in a Rake task and run them when the app is deployed. If you're using Sqlite, this would create the database (although on some hosts you are not allowed to update the file system). I don't think it's a good idea to use Sqlite for a production database, but that's your decision.
Since the auto_upgrade! is wrapped in :development block, it won't be called on production server. How am I supposed to upgrade database when I add or remove columns in it?
Use a Rake task. After each deployment you'd run the "db:migrate:up" (or whatever you'd called it) task and it would run the latest migrations. You might get a few ideas from Padrino's Rake tasks for DataMapper

Accessing Sinatra application scope from Rake task

I have a global variable in a Sinatra application that I want to update with a scheduled task from my Rakefile. Note that the application is hosted on Heroku. I have set up helpers in order to access this variable.
get '/' do
##var
end
helpers do
def get_var
return ##var
end
def set_var(value)
##var = value
end
end
Here is the task in my Rakefile:
task :do_something do
Sinatra::Application.set_var(get_data)
end
def get_data
# Retrieve value from external source
...
return val
end
The problem I run into is that the task executes properly, but the variable in the Sinatra application is never updated. I assume this is because calling Sinatra::Application from within the Rakefile actually creates a separate instance of the application from the primary instance that I am trying to update.
I want to know if their is a way to access the scope of the running Sinatra web app from within a Rakefile task.
*Note: I could just write the value retrieved in the scheduled task to a database and then access it from the Sinatra app, but that would be overkill because this variable is updated so infrequently but retrieved so regularly that I would prefer to keep it in memory for easier access. I have looked into Memcache and Redis in order to avoid turning to a database, but again I feel that this would be excessive for a single value. Feel free to disagree with this.
EDIT: In regards to Alexey Sukhoviy's comment, Heroku does not allow writing to files outside of the tmp directories, and these are not kept alive long enough to satisfy the needs of the application.
I ended up storing the variable using Memcache. This plays well with Heroku since they provide a free add-on for it. The Dalli gem provides a simple interface with Ruby for Memcache. In my Sinatra app file, I set the following options:
require 'dalli'
set :cache, Dalli::Client.new
I then am able to recover the stored variable from the Rakefile:
task :do_something do
Sinatra::Application.settings.cache.set('var', get_data)
end
I can then access this variable again in my Sinatra controller:
settings.cache.get('var')

Resources