Comatose, Authlogic and FCKEditor
Ok so we are using comatose and Authlogic for an app we are building for a client. We also wanted to use FCKEditor for comatose to give it a little more buzz.
Firstly you need to install Comatose. Go to your project root directory in terminal and type the following.
./script/plugin source http://mattmccray.com/svn/rails/plugins ./script/plugin install comatose ./script/generate comatose_migration rake migrate
Then you need to install fckEditor. To do so go to the root of your app in terminal and type the following
ruby script/plugin install svn://rubyforge.org//var/svn/fckeditorp/trunk/fckeditor
In the Comatose _form.html.erb page you need to change
<%= f.text_area :body, :rows=>20, :tabindex=>2 %>
to this so that the fckeditor appears when creating and editing pages.
<%= fckeditor_textarea('page', 'body', :width => '100%', :height => '500px') %>
Once you have Comatose and FCKEditor installed and running the final step is to get it all working with Authlogic.
So in your environment.rb file you need to add the following.
Comatose.configure do |config|
#Custom class we wrote to handle current_user etc
config.admin_includes << :user_methodss
# Calls :login_required as a before_filter
config.admin_authorization = :require_user
end
This will force comatose to have require a user to be logged in to use the system. The :user_methodss class is a class we wrote to handle the login methods of Autlogic. You can replace this with your own if you want ill include the class we created below.
module UserMethods
module ClassMethods
def permission_required(permission_name,actions, notice=nil)
notice ||= "You don't have access to that part of the site."
actions = [actions].flatten
before_filter(:only => actions) { |controller| require_or_redirect(permission_name, controller, notice) }
end
def require_or_redirect(permission_name, controller, notice)
user = controller.send(:current_user)
if !user.can?(permission_name)
# @permission_missing is used for should_require_permission test
controller.instance_variable_set("@permission_missing", true)
controller.send(:redirect_back_or_to, "/", notice)
end
end
end
def self.included(base)
base.extend(ClassMethods)
end
protected
# Redirects back or if that fails, redirects to the supplied path
# Also accepts a notice if you want to flash something
def redirect_back_or_to(path, notice=nil)
flash[:notice] = notice unless notice.blank?
begin
redirect_to :back
rescue ActionController::RedirectBackError
redirect_to path
end
end
# Returns the param to use in a find command for objects with a
# possible cross-db sort
def cross_database_order(order, direction, sort_methods_allowed)
return "#{ order } #{ direction }" if !cross_database_sort?(order, sort_methods_allowed)
end
# Returns true if the given order looks like a cross db sort
# Allowed_methods should be an array of association objects to
# methods allowed to be called on them.
def cross_database_sort?(order, allowed_methods)
return allowed_methods.include?(order)
end
# Performs a sort on the given objects by calling methods rather than
# using a db lookup.
def cross_database_sort(objects_to_sort, order, direction, sort_methods_allowed)
if cross_database_sort?(order, sort_methods_allowed)
methods = order.split(".")
association_name, method = order.split(".")
objects_to_sort = objects_to_sort.sort_by do |object|
methods.each do |meth|
next if object.nil?
object = object.send(meth)
end
"#{ object }"
end
objects_to_sort.reverse! if direction == "desc"
end
return objects_to_sort
end
private
# ActionMailer views don't have access to the request, so we need
# to set these variables manually.
def setup_host_for_mail
ActionMailer::Base.default_url_options[:host] = request.host_with_port
end
def logout
current_user_session.destroy if current_user_session
end
def current_user_session
return @current_user_session if defined?(@current_user_session)
@current_user_session = UserSession.find
end
def current_user
return @current_user if defined?(@current_user)
@current_user = current_user_session && current_user_session.user
end
def require_user
unless current_user
store_location
flash[:notice] = "You must be logged in to access this page"
redirect_to new_user_session_url
return false
end
end
def require_no_user
if current_user
store_location
flash[:notice] = "You must be logged out to access this page"
redirect_to "/"
return false
end
end
def store_location
session[:return_to] = request.request_uri
end
def redirect_back_or_default(default)
redirect_to(session[:return_to] || default)
session[:return_to] = nil
end
end
Worth noting the “ss” in user_methodss is not a mistake. Because of the way Comatose handles the string/symbol you pass in it wouldn’t render :user_methods but instead looked for :users_methods which was incorrect so this was our little hack to get around that.
Adding your own login method to Authlogic
So on a new project we are working on we have a need for a user to be able to login via either their “Login” or “Mobile” number. Now we are using the Authlogic gem which is a great gem and comes with all default methods for login etc and allows you to customise this very easily.
So firstly you need to add the following to your UserSession model. What this does is overwrite the default login method with the one we are defining below called “find_by_username_or_mobile”.
class UserSession < Authlogic::Session::Base find_by_login_method :find_by_username_or_mobile end
Then in your user model its as simply as creating the class method for login. Now of course the password is still apart of the login process but we only wanted to allow users to either login via their login or mobile so no need to change the password methods.
class User < ActiveRecord::Base
def self.find_by_username_or_mobile(login)
find_by_login(login) || find_by_mobile(login)
end
end
So give it a try and let us know how you go hope this helps
Formatting Paypal dates
We have been doing a some work on PayPal integration for one of our clients for their soon to be released application and l needed to reformat the date PayPal was sending me. Now l know that Active Merchant could help with this but it didn’t fit our application.
So any ways PayPal sends you a date like so “03:25:17 Apr 26, 2007 PDT” and l need it in a clean format so here is what l came up with, its a first run and l am sure l will change it when the time comes to refactor but for now it works.
def self.date_from_paypal(datetime_string)
datetime_string =~ /(d+):(d+):(d+) (.+) (d+), (d+)/
parseable_string = "#$6-#$4-#$5T#$1:#$2:#$3"
DateTime.parse(parseable_string)
end
%w(payment_date).each do |attrib|
module_eval %{
def #{attrib}=(datetime_string)
write_paypal_date :#{attrib}, datetime_string
end
}
end
private
def write_paypal_date(attribute, datetime_string)
write_attribute attribute, PaypalTransaction.date_from_paypal(datetime_string)
end
So what it does is when you go to set the “payment_date” field it runs the “write_paypal_date” method which formats the date for you a little cleaner. You can add other dates to this very simply by just adding them to the string array in the method above.
Sentia rails application templates now on GitHub
We have just made a project on github to store our rails application templates that we talked about here. You can check it out here. Enjoy
Open source flash charts like google analytics
We all want our charts to look like the ones in google analytics. Well know there is a way the “Open Flash Chart” project. The guys over at pull monkey have released a plugin for rails that helps you get in these great charts. Ill be testing this plugin very soon and ill put up my experience and a little walk through. In the mean time if you want to check out the project have a look here
Here is an example of what the charts look like

Ajax.Updater and javascript
Ran into a little problem today which made me think for a second. I have a Javascript function that runs once a calendar control is closed. It just passes a parameter to a action which renders a view nothing fancy.
So my onClose function looks like so
function onClose(cal) {
var p = cal.params;
new Ajax.Updater('overlapping', '/visits/new', {
parameters: { start_date: p.inputField.value; },
evalScripts: true
});
cal.hide();
};
This will fire once the calendar is closed. ‘Overlapping’ is the ID of the Div ill be updating and ‘/visits/new’ is the path of the action in your controller. This will then pass the start date param to the action which can then be used in the view. The problem l had is that l had some javascript on the partial that was not executing. Had to think for a minute and then it turned out that evalScripts is false by default thus the javascript was not executing.
So its as simple as having the following as a param in your Ajax.updater
evalScripts: true
Once you have done that your good to go.




