Not that this doesn't support multiple layout rendering. Only the last layout rendered is stored.
Take a look at the Example Usage in the comments above the matcher for usage information.
Giving back to the development community.
Not that this doesn't support multiple layout rendering. Only the last layout rendered is stored.
Take a look at the Example Usage in the comments above the matcher for usage information.
mkdir -p ext/apache2/module_libboost_oxt g++ -Iext -fPIC -fvisibility=hidden -DVISIBILITY_ATTRIBUTE_SUPPORTED -DDARWIN -DSIGPROCMASK_SETS_THREAD_MASK -I/usr/include/apr-1 -I/usr/include/apr-1 -I/usr/include/apache2 -arch i386 -arch ppc -arch x86_64 -arch ppc64 -D_REENTRANT -I/usr/local/include -DHASH_NAMESPACE="__gnu_cxx" -DHASH_FUN_H="" -DHAS_SFENCE -DHAS_LFENCE -Wall -g -DPASSENGER_DEBUG -DBOOST_DISABLE_ASSERTS -o ext/apache2/module_libboost_oxt/aggregate.o -c ext/apache2/module_libboost_oxt/aggregate.cpp mkdir -p ext/apache2/module_libboost_oxt rm -rf ext/apache2/module_libboost_oxt.a ar cru ext/apache2/module_libboost_oxt.a ext/apache2/module_libboost_oxt/aggregate.o ranlib ext/apache2/module_libboost_oxt.a gcc -Iext -Iext/common -fPIC -fvisibility=hidden -DVISIBILITY_ATTRIBUTE_SUPPORTED -DDARWIN -DSIGPROCMASK_SETS_THREAD_MASK -I/usr/include/apr-1 -I/usr/include/apr-1 -I/usr/include/apache2 -arch i386 -arch ppc -arch x86_64 -arch ppc64 -D_REENTRANT -I/usr/local/include -DHASH_NAMESPACE="__gnu_cxx" -DHASH_FUN_H=" " -DHAS_SFENCE -DHAS_LFENCE -Wall -g -DPASSENGER_DEBUG -DBOOST_DISABLE_ASSERTS -o ext/apache2/mod_passenger.o -c ext/apache2/mod_passenger.c g++ -Iext -Iext/common -fPIC -fvisibility=hidden -DVISIBILITY_ATTRIBUTE_SUPPORTED -DDARWIN -DSIGPROCMASK_SETS_THREAD_MASK -I/usr/include/apr-1 -I/usr/include/apr-1 -I/usr/include/apache2 -arch i386 -arch ppc -arch x86_64 -arch ppc64 -D_REENTRANT -I/usr/local/include -DHASH_NAMESPACE="__gnu_cxx" -DHASH_FUN_H=" " -DHAS_SFENCE -DHAS_LFENCE -Wall -g -DPASSENGER_DEBUG -DBOOST_DISABLE_ASSERTS -o ext/apache2/Configuration.o -c ext/apache2/Configuration.cpp g++ -Iext -Iext/common -fPIC -fvisibility=hidden -DVISIBILITY_ATTRIBUTE_SUPPORTED -DDARWIN -DSIGPROCMASK_SETS_THREAD_MASK -I/usr/include/apr-1 -I/usr/include/apr-1 -I/usr/include/apache2 -arch i386 -arch ppc -arch x86_64 -arch ppc64 -D_REENTRANT -I/usr/local/include -DHASH_NAMESPACE="__gnu_cxx" -DHASH_FUN_H=" " -DHAS_SFENCE -DHAS_LFENCE -Wall -g -DPASSENGER_DEBUG -DBOOST_DISABLE_ASSERTS -o ext/apache2/Bucket.o -c ext/apache2/Bucket.cpp g++ -Iext -Iext/common -fPIC -fvisibility=hidden -DVISIBILITY_ATTRIBUTE_SUPPORTED -DDARWIN -DSIGPROCMASK_SETS_THREAD_MASK -I/usr/include/apr-1 -I/usr/include/apr-1 -I/usr/include/apache2 -arch i386 -arch ppc -arch x86_64 -arch ppc64 -D_REENTRANT -I/usr/local/include -DHASH_NAMESPACE="__gnu_cxx" -DHASH_FUN_H=" " -DHAS_SFENCE -DHAS_LFENCE -Wall -g -DPASSENGER_DEBUG -DBOOST_DISABLE_ASSERTS -o ext/apache2/Hooks.o -c ext/apache2/Hooks.cpp g++ -flat_namespace -bundle -undefined dynamic_lookup ext/apache2/Configuration.o ext/apache2/Bucket.o ext/apache2/Hooks.o ext/apache2/mod_passenger.o -fPIC -o ext/apache2/mod_passenger.so -fPIC -fvisibility=hidden -DVISIBILITY_ATTRIBUTE_SUPPORTED -DDARWIN -DSIGPROCMASK_SETS_THREAD_MASK -I/usr/include/apr-1 -I/usr/include/apr-1 -I/usr/include/apache2 -arch i386 -arch ppc -arch x86_64 -arch ppc64 -D_REENTRANT -I/usr/local/include -DHASH_NAMESPACE="__gnu_cxx" -DHASH_FUN_H=" " -DHAS_SFENCE -DHAS_LFENCE -Wall -g -DPASSENGER_DEBUG -DBOOST_DISABLE_ASSERTS ext/apache2/module_libpassenger_common.a ext/apache2/module_libboost_oxt.a -fPIC -L/usr/lib -lapr-1 -L/usr/lib -laprutil-1 -lpthread ld: warning: in /usr/lib/bundle1.o, missing required architecture ppc64 in file ld: warning: in /usr/lib/libapr-1.dylib, missing required architecture ppc64 in file ld: warning: in /usr/lib/libaprutil-1.dylib, missing required architecture ppc64 in file ld: warning: in /usr/lib/libpthread.dylib, missing required architecture ppc64 in file ld: warning: in /usr/lib/gcc/powerpc-apple-darwin10/4.2.1/libstdc++.dylib, missing required architecture ppc64 in file ld: warning: in /usr/lib/libSystemStubs.a, missing required architecture ppc64 in file ld: warning: in /usr/lib/libSystem.dylib, missing required architecture ppc64 in file ld: symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o) for architecture ppc64 collect2: ld returned 1 exit status lipo: can't open input file: /var/tmp//ccPTqixF.out (No such file or directory) rake aborted! Command failed with status (1): [g++ -flat_namespace -bundle -undefined dyn...]
Fix the compilation errror
/Users/karl/.rvm/gems/ree-1.8.7-2010.02/gems/passenger-3.0.5/lib/phusion_passenger/platform_info/ruby.rb:166:in `expand_path': couldn't find HOME environment -- expanding `~/.rvm' (ArgumentError) from /Users/karl/.rvm/gems/ree-1.8.7-2010.02/gems/passenger-3.0.5/lib/phusion_passenger/platform_info/ruby.rb:166:in `_unmemoized_rvm_path' from /Users/karl/.rvm/gems/ree-1.8.7-2010.02/gems/passenger-3.0.5/lib/phusion_passenge
Fix the missing HOME env variable
Hard-code the path to your HOME directory.To find the location of your gem files you can echo $GEM_HOME. Keep in mind you will need to substitute your own HOME path in the above command.
Update 2010-03-17: Don't fail in test mode if we can't find a user
I haven't been able to find any information on authenticating users in Rails Metal controllers. So I took a look at what was available in the session and worked with that. I'm not an expert on Authlogic (I did write an Authlogic Add-On a while ago) but this seems like a good solution. Let me know if you know of any problems with this approach.I added a method to UserSession (or add it to whatever class you use for your sessions) that takes the Metal env and checks the authentication parameters and returns the user record. I don't bother with updating the user's last_request_at attributes or anything. I had to bypass the Authlogic session entirely because Authlogic needs to be activated with a controller before you can use the session stuff. I considered dummying the controller by including authlogic/test_case but I don't know enough about what the dummy controller does regarding authentication to go this route.
And the code...
Here's the Metal "controller":
A couple neat things in the Metal controller are the use of ActionController::Request.new(env) so we have access to request.remote_ip and other helper methods this class provides.
The part where I validate the user is:
I've written a Rake helper to silence both. You can adapt it for other uses, but I think it's mostly relevant in Rake tasks.
# lib/rake_helpers.rb
module Rake
module Helpers
# Silence the Rails logger as well as the SQL logger
# Call with a block e.g
# silent { my block code }
def silent
ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
alias_method :original_log_info, :log_info
def silent_log_info(*args); end
alias_method :log_info, :silent_log_info
end
@@old_logger = ActiveRecord::Base.logger
ActiveRecord::Base.logger = Class.new { def method_missing(*args); end; }.new
yield
ActiveRecord::Base.logger = @@old_logger
ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
alias_method :log_info, :original_log_info
end
end
end
end
And sample usage:
# lib/tasks/db.rake
require 'rake_helpers'
include Rake::Helpers
namespace :db do
namespace :update do
desc "Update counter caches"
task :counters => :environment do
silent do
ActiveRecord::Base.transaction do
[Artist, Album].each do |model|
model.find_in_batches(:batch_size => 5000) do |batch|
batch.each { |record| record.update_counts }
end
end
end
end
end
end
end
So integration tests will have to do. I had problems with using response.should be_success. The docs say it exists, but it doesn't for me. YMMV.
Anyways, here is my Metal class along with the integration test:
Sample usage:
$ renv RAILS_ENV is unset $ renv p RAILS_ENV set to production $ renv d RAILS_ENV set to development $ renv s RAILS_ENV set to staging $ renv t RAILS_ENV set to test $ renv RAILS_ENV is test
And the code:
# Put this in your ~/.profile
function renv() {
rails_env_p="production"
rails_env_d="development"
rails_env_s="staging"
rails_env_t="test"
if [ $1 ];then
eval 'rails_env=${rails_env_'"${1}"'}'
export RAILS_ENV=$rails_env
echo "RAILS_ENV set to $RAILS_ENV"
elif [ $RAILS_ENV ];then
echo "RAILS_ENV is $RAILS_ENV"
else
echo "RAILS_ENV is unset"
fi
}
(Here's a handy bash script I wrote to easily switch between your Rails environments.)
So I decided to do something about it and protect destructive or database altering rake tasks from being run in the production environment. I really like this approach and I think I'll use it in future projects regardless of the setup. The fact is you only do a rake db:reset in production once, during the cold deploy of your app. It allows rake db:migrate and its variants, but not rake db:migrate:reset. Look at the code for the full list of restricted rake tasks. The tasks in PROTECT_SOME are matched explicitly, PROTECT_ALL restricts all variants of that task.
This shows the warning message and confirmation that appear. If you know what you are doing, or you want to automate things with Capistrano and need to run one of the protected tasks just pass FORCE=true to the task.
[deployer@rails1 ~/rails_apps/rails1.creagency.com.au/current] echo $RAILS_ENV production [deployer@rails1 ~/rails_apps/rails1.creagency.com.au/current] rake db:reset (in /www/rails_apps/rails1.creagency.com.au/releases/20091204033227) **************************************************************************** * WARNING! You are in the PRODUCTION environment and are running a Rake task * that will DESTROY your PRODUCTION database! * * If you know what you are doing you can run this task with FORCE=true to * prevent this message appearing. **************************************************************************** Are you sure? (Yes|No) [No] Quitting. [deployer@rails1 ~/rails_apps/rails1.creagency.com.au/current]And here is the code. Just add it to the bottom of your application's Rakefile:
The Capistrano deployment recipe had been changed to forward the ssh agent (which means that my local ssh key is the one that will be used by the deployment server to checkout the updated code from Git):
ssh_options[:forward_agent] = trueCapistrano was complaining:
servers: ["10.5.23.203"]
[10.5.23.203] executing command
** [10.5.23.203 :: out] Permission denied (publickey).
** [10.5.23.203 :: out] fatal: The remote end hung up unexpectedly
The solution was just to add my SSH key to my local SSH agent:
$ ssh-addSimple enough. Turns out you have to do that every time you restart your machine tho, which is a bit annoying. Any way to avoid that?
Cheers, Karl
As you probably know, the best thing to do is to develop in a branch and rebase against master often (never rebase a remote branch). This ensures that your changes are always the latest changes applied to the index. And because they're applied on top of the index, when you merge them into the master branch and push, it's just a fast-forward update and you will never have to do a merge.
But what happens if you've been working on the master branch for a while? Is it too late? I just encountered this myself, and here's how you can keep the master merge-free in this situation.
git fetch # have there been changes to master since you last fetched/pulled? if not, you can just commit and push, otherwise... git commit -a -m "awesome message here" # commit your changes git branch wip # create a new branch with your changes git reset --hard HEAD~1 # reset the master branch to before your commit(s) git checkout wip continue working... git fetch origin master git rebase origin/master # rebase your changes on top of master often all done... git rebase -i origin/master # preferably squash your commits git checkout master git pull # make sure master has the latest code git merge wip # apply your fast-forward changes to the index git push # quick before someone else does!
Can this process be shortened? Let me know if you have ideas.
Here are some excellent articles explaining some Git best-practices. There is some excellent info here, even from Linus himself!
Let me know if you have good Git articles. I'm still learning about Git, but now that I'm getting my head around it, it's getting better and better!
Karl
// Add styles to an element to show the image in *image* at the given *x_pos* and *y_pos*.
// If the optional *x_size* or *y_size* arguments are passed in, the width and/or height
// is set to that value.
=sprite(!image, !x_pos, !y_pos, !x_size=0, !y_size=0)
:background-image = url(!image)
:background-position = !x_pos !y_pos
@if !x_size > 0
:width = !x_size
@if !y_size > 0
:height = !y_size
I'd recommend wrapping the mixin for your sprite image, because you're going to use it a lot. For example:
=player_sprite(!x_pos, !y_pos, !x_size=0, !y_size=0)
+sprite("/images/player-sprite.png", !x_pos, !y_pos, !x_size, !y_size)
// Now define some styles using the player sprite
.playlists-icon
+player_sprite(-600px, 0, 18px, 18px)
.recently-played-icon
+player_sprite(-700px, 0, 18px, 18px)
.playing-now-icon
+player_sprite(-800px, 0, 18px, 18px)
This will generate the following CSS
.playlists-icon {
background-image: url('/images/player-sprite.png');
background-position: -600px 0;
width: 18px;
height: 18px; }
.recently-played-icon {
background-image: url('/images/player-sprite.png');
background-position: -700px 0;
width: 18px;
height: 18px; }
.playing-now-icon {
background-image: url('/images/player-sprite.png');
background-position: -800px 0;
width: 18px;
height: 18px; }
And your Haml to display the divs with the images is as simple as:
.playlists-icon .recently-played-icon .playing-now-iconAwesome! Now that's easy! If you found this useful, let me know!