Entries Tagged 'Ruby' ↓
July 11th, 2008 — Rails, Ruby
It’s been quite a while since my last Ruby on Rails post so let’s go over a little “gotcha” that you might encounter when using the restful_authentication plugin.
Getting started with restful_authentication is fairly easy. After installing the plugin it’s just a matter of running the following generate command:
script/generate authenticated user sessions
This will create a migration for a users table, a model and controller for users and a sessions controller. It will also add some named routes to config/routes.rb.
So far so good, right? Well, a common mistake when generating the model and controllers is to user the singular form of both user and session. The command will run successfully and do exactly what you told it to do. You won’t become aware of a problem until you try to log in for the first time and see this:
NameError in SessionsController#create
uninitialized constant SessionsController
RAILS_ROOT: C:/rails/bookmarks
Application Trace |
Framework Trace |
Full Trace
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:278:in `load_missing_constant'
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:467:in `const_missing'
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:479:in `const_missing'
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/inflector.rb:283:in `constantize'
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/core_ext/string/inflections.rb:143:in `constantize'
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.0/lib/action_controller/routing/route_set.rb:386:in `recognize'
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.0/lib/action_controller/dispatcher.rb:148:in `handle_request'
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.0/lib/action_controller/dispatcher.rb:107:in `dispatch'
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.0/lib/action_controller/dispatcher.rb:104:in `synchronize'
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.0/lib/action_controller/dispatcher.rb:104:in `dispatch'
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.0/lib/action_controller/dispatcher.rb:120:in `dispatch_cgi'
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.0/lib/action_controller/dispatcher.rb:35:in `dispatch'
c:/ruby/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/webrick_server.rb:112:in `handle_dispatch'
c:/ruby/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/webrick_server.rb:78:in `service'
c:/ruby/lib/ruby/1.8/webrick/httpserver.rb:104:in `service'
c:/ruby/lib/ruby/1.8/webrick/httpserver.rb:65:in `run'
c:/ruby/lib/ruby/1.8/webrick/server.rb:173:in `start_thread'
c:/ruby/lib/ruby/1.8/webrick/server.rb:162:in `start'
c:/ruby/lib/ruby/1.8/webrick/server.rb:162:in `start_thread'
c:/ruby/lib/ruby/1.8/webrick/server.rb:95:in `start'
c:/ruby/lib/ruby/1.8/webrick/server.rb:92:in `each'
c:/ruby/lib/ruby/1.8/webrick/server.rb:92:in `start'
c:/ruby/lib/ruby/1.8/webrick/server.rb:23:in `start'
c:/ruby/lib/ruby/1.8/webrick/server.rb:82:in `start'
c:/ruby/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/webrick_server.rb:62:in `dispatch'
c:/ruby/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/commands/servers/webrick.rb:66
c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:509:in `require'
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:354:in `new_constants_in'
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:509:in `require'
c:/ruby/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/commands/server.rb:39
c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
script/server:3
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:278:in `load_missing_constant'
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:467:in `const_missing'
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:479:in `const_missing'
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/inflector.rb:283:in `constantize'
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/core_ext/string/inflections.rb:143:in `constantize'
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.0/lib/action_controller/routing/route_set.rb:386:in `recognize'
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.0/lib/action_controller/dispatcher.rb:148:in `handle_request'
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.0/lib/action_controller/dispatcher.rb:107:in `dispatch'
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.0/lib/action_controller/dispatcher.rb:104:in `synchronize'
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.0/lib/action_controller/dispatcher.rb:104:in `dispatch'
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.0/lib/action_controller/dispatcher.rb:120:in `dispatch_cgi'
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.1.0/lib/action_controller/dispatcher.rb:35:in `dispatch'
c:/ruby/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/webrick_server.rb:112:in `handle_dispatch'
c:/ruby/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/webrick_server.rb:78:in `service'
c:/ruby/lib/ruby/1.8/webrick/httpserver.rb:104:in `service'
c:/ruby/lib/ruby/1.8/webrick/httpserver.rb:65:in `run'
c:/ruby/lib/ruby/1.8/webrick/server.rb:173:in `start_thread'
c:/ruby/lib/ruby/1.8/webrick/server.rb:162:in `start'
c:/ruby/lib/ruby/1.8/webrick/server.rb:162:in `start_thread'
c:/ruby/lib/ruby/1.8/webrick/server.rb:95:in `start'
c:/ruby/lib/ruby/1.8/webrick/server.rb:92:in `each'
c:/ruby/lib/ruby/1.8/webrick/server.rb:92:in `start'
c:/ruby/lib/ruby/1.8/webrick/server.rb:23:in `start'
c:/ruby/lib/ruby/1.8/webrick/server.rb:82:in `start'
c:/ruby/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/webrick_server.rb:62:in `dispatch'
c:/ruby/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/commands/servers/webrick.rb:66
c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:509:in `require'
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:354:in `new_constants_in'
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:509:in `require'
c:/ruby/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/commands/server.rb:39
c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
script/server:3
Request
Parameters:
{"commit"=>"Log in",
"authenticity_token"=>"0c0f07222da8ed58d8c6ebcafb9bf32f0bc84143",
"login"=>"anthony",
"password"=>"mysupersecretpassword"}
Uh oh! what went wrong? It looks like Rails is looking for a controller called SessionsController. But we generated one named SessionController. Why is this happening? Take a look in the views/session/new.html.erb file.
<% form_tag session_path do -%>
<p><label for="login">Login</label><br/>
<%= text_field_tag 'login' %></p>
<p><label for="password">Password</label><br/>
<%= password_field_tag 'password' %></p>
<!-- Uncomment this if you want this functionality
<p><label for="remember_me">Remember me:</label>
<%= check_box_tag 'remember_me' %></p>
-->
<p><%= submit_tag 'Log in' %></p>
<% end -%>
The form_tag target is session_path. session_path is created for us by magic because of its mapping in routes.rb.
map.resource :session
When mapping a resource like this Rails looks for the controller with the pluralized name of the resource name by default, which means session_path is getting SessionsController. We can change the behavior by explicitly setting the controller for the resource.
map.resource :session, :controller => :session
Try to log in again and you will be authenticated! Of course it may just be easier to remember to use the pluralized name of whatever controller you want to use for managing sessions.
February 4th, 2008 — Java, Personal, Rails, Ruby, architecture, career, scalability, work
I’ve been digging around lately for a Boston area user group dedicated to architectural scalability and I haven’t been able to find one. Other user groups that I regularly attend have meetings centered around scalability once in a while, but I’m looking for something with a schedule dedicated to the topic. It’s a hot topic in the industry right now with a lot happening on different fronts and there should be some ongoing professional discussion dedicated what goes into growing an application.
Here are some of the topics I want to talk about:
- Data growth and access - What kind of DBMS topologies allow maximum scalability without breaking the budget? What if the budget wasn’t a problem? How do you migrate your data model from hundreds of users to millions of users? Should you partition user data across shards or keep it in a central database? How do you profile data access paterns? Is your application mostly-read or mostly-write? When should you use an LDAP directory for data storage? When should you use MySQL and when should you use Oracle?
- Application server scaling - app server clustering, web server integration, load balancing, application session management, data caching
- Web Tier - load balancing reverse proxies, data caching, working with HTTP, considerations for exposing functionality via REST
- Language conisderations and platform choices - Dynamic languages vs. Static languages, Linux vs. Windows, Solaris vs. Linux, RedHat vs. Oracle, IBM vs. Oracle - How do you make these choices? What evaluation critera are most important? Which ones are misleading?
- Framework scalability - How can you scale if your framework can’t? Does Rails really scale better than Spring Web MVC? Where do PHP frameworks fit in? What are the alternatives? This is where we will investigate what you gain and lose by binding yourself to a particular framework, how to keep the coupling to a minimum and how to use your framework as a solid foundation instead viewing it as a cage.
- Emerging technology - Should you become familiar with Map Reduce and Hadoop? What kind of impact do object databases have on your application? Should you buy your own Sun or Dell boxes or use Amazon’s EC2 and S3?
- Application architecture - How do you write an application that scales? What does your application look like as it grows from servicing hundreds to millions of users? How does it handle session management? How does it access datastores? Are there any design patterns that are helpful? What are the anti-patterns to be aware of?
Like I said, I haven’t found a group dedicated to discussing these topics. If you know of one in the Boston area please let me know. Assuming there isn’t one I am willing to start one. I’d like to start off small and meet at coffee shops around Burlington or Lowell. I have no delusions that this is going to start off or even become as big as NEJUG is now. If it starts off as a few people getting together to talk about scalability trends, cool caching solutions and specific products then I’d call it a good start.
The meeting location is still TBD and will be based on how many people are interested in attending. It will probably be somewhere in Burlington, MA. There is no planned presentation at this time. Instead we will have a meet and greet and then discuss scalability trends and news, what approaches to scalability are commonly used now and what are the plans for the future.
If you are interested in coming or in finding out more information please email me at <my first name>@<my domain name>.<my tld> or leave a comment below. Please make sure to include your email address when you fill out the form so that I can get in touch with you - your email address will not be displayed on my site.
July 1st, 2006 — Ruby
Ruby allows the creation of modules that provide namespaces for methods and constants to live. They are also used to mixin these methods and constants into classes. These mixed-in modules provide a class with references to whatever is defined within the module. Below is a small (meaningless) Ruby module.
module AnthonyModule
CONST_DATA = "I am a constant from AnthonyModule"
def who_am_i
puts "My name is: #{@name}"
end
def ten_times write_me
10.times { puts "#{write_me}" }
end
end
This module provides two methods and one constant. When this module is mixed in with a class these methods will become instance methods of the class. Below is an example of using the require method to load the AnthonyModule.rb file and the include method to reference the module in the class.
require "AnthonyModule"
class MyClass
include AnthonyModule
def initialize name
@name = name
end
end
Notice this class does not have a method called ten_times defined in it. However when an instance of this class is created it will have a ten_times method because the AnthonyModule is included. A call to this method is shown below.
m = MyClass.new "Instance 1"
m.ten_times "Hello modules!"
This will produce ten lines each with “Hello modules!” printed on it. Now what happens if another module is introduced that provides another method also named ten_times?
module NewModule
CONST_DATA = "I am a constant in newmodule.rb"
def ten_times multiply_me
puts "ten times #{multiply_me} is: #{ 10 * multiply_me }"
end
end
Using require and include to mix in NewModule into the class there are now two methods with the same name and signature in the class. Because Ruby looks in the module included last in a class it will find the NewModule#ten_times method before the AnthonyModule#ten_times method. Running the sample code gives an error now.
ruby/NewModule.rb:5:in `*': String can't be coerced into Fixnum (TypeError)
The problem here is that Ruby does not know how to multiply a number by a string. I don't want to do this though, I want to print out my message ten times. Because I'm calling the ten_times method outside of the class I can't specify exactly which ten_times method I want to call. Ruby picks the first one it finds searching backwards (upwards) through the include list. It appears as though using mixed in methods with a name clash outside of the class can not be done. If the module's methods were called in some class methods the module name could be used to differentiate between which method should be called. Outside the class there is no such luck.
I'll be starting a Rails app later.
Anthony
June 26th, 2006 — Ruby
I made quite a bit of progress in reading the Pick Axe Book over the weekend. I wrote a little program to reflect what I read and to scratch an itch of mine too.
I have three processes that I want to run at all times if it can be helped, but it's ok if there is some downtime for each. Whether these processes are started at system boot time or any time later doesn't make a difference to me, if they go down I want to start them back up. For a (very short) time I just blindly used the cron for my user account to start the processes once every X hours. Unfortunately this meant that five instances of the Unreal Tournament 2004 server would be running at once. svnserve would fail and send me email every few hours when it was invoked and JBoss would consume far too many resources because it was running too many instances. Using the cron to blindly kick off the servers was a bad idea.
Because I wanted to use the cron or an equivalent to periodically check on the servers I had to come up with a way to determine if the servers were already running before trying to start them again. I came up with two short Ruby scripts to solve this problem. The first is a class to represent the process to monitor and start.
class ProcessMonitor
def initialize(name, processString, restartCmd)
@name, @processString, @restartCmd = name, processString, restartCmd
end
def get_process_list
@ps = IO.popen("ps -ef", "r")
end
def is_running?
re = Regexp.new(".*?#{@processString}.*?")
@ps.each do | line |
if re.match(line)
return true
end
end
return false
end
def restart_process
puts "Process is not running. Trying to restart."
process = Process.fork { system("#{@restartCmd}") }
Process.detach(process)
end
def run
get_process_list
if !is_running?
restart_process
end
end
end
The constructor takes a name (which doesn't do anything at this point), a substring of the process to look for in the ps output and the command used to restart the process if it isn't running. The get_process_list serves only to get a ps listing of all the processes running.
The is_running? method examines each entry in the listing until it finds a process that matches the processString snippet passed in when the object was created. The run method will execute the restartCmd string only if the process is not running. The restart_process method uses the Process.fork method to start the command as a process outside the current Ruby interpreter. It then detaches any interest in that long running process, enabling the Ruby interpreter to exit normally.
I should point out that I had some trouble debugging what turned out to not be a problem. I developed this class in Eclipse using and the Ruby interpreter would not terminate when run from inside Eclipse. Running the program on the command line works without this strange hang.
Because I do not want to provide a cron entry to call this class for each process I want to monitor I have written a small driver class that takes input from a file.
require "process_monitor"
filename = ARGV[0]
processes = Array.new
IO.foreach(filename) do | line |
params = Array.new
line.each("::") do | param |
params
This script takes one filename as its argument. Each line in the file should contain a “::”-delimited list of parameters to create a ProcessMonitor object with. After parsing each line a new ProcessMonitor object is created and run in a new thread. After all threads have been run the script waits for each to finish and the program exits. I plan to put error handling and write test cases sometime this week.