<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Off you go... into the purple yonder! &#187; Rails</title>
	<atom:link href="https://ward.vandewege.net/blog/category/rails/feed/" rel="self" type="application/rss+xml" />
	<link>https://ward.vandewege.net/blog</link>
	<description></description>
	<lastBuildDate>Sun, 12 May 2024 20:57:05 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
		<item>
		<title>acts_as_paranoid and acts_as_versioned on Rails 3</title>
		<link>https://ward.vandewege.net/blog/2011/04/acts_as_paranoid-and-acts_as_versioned-on-rails-3/</link>
		<comments>https://ward.vandewege.net/blog/2011/04/acts_as_paranoid-and-acts_as_versioned-on-rails-3/#comments</comments>
		<pubDate>Fri, 01 Apr 2011 18:24:22 +0000</pubDate>
		<dc:creator><![CDATA[ward]]></dc:creator>
				<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://ward.vandewege.net/blog/?p=593</guid>
		<description><![CDATA[A few years ago, I described how to combine acts_as_paranoid and acts_as_versioned in order to make deleted records end up in your versioning tables. In order to do the same thing under Rails 3, I had to make a few &#8230; <a href="https://ward.vandewege.net/blog/2011/04/acts_as_paranoid-and-acts_as_versioned-on-rails-3/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>A few years ago, <a href="http://ward.vandewege.net/blog/2007/02/acts_as_paranoid-and-acts_as_versioned/">I described</a> how to combine acts_as_paranoid and acts_as_versioned in order to make deleted records end up in your versioning tables.</p>
<p>In order to do the same thing under Rails 3, I had to make a few adjustments. First of all, you need the rails3_acts_as_paranoid gem, which is a <a href="https://github.com/goncalossilva/rails3_acts_as_paranoid">total rewrite of acts_as_paranoid for rails 3</a>. Add these lines to your Gemfile:</p>
<pre>
gem 'rails3_acts_as_paranoid'
gem 'acts_as_versioned'
</pre>
<p>Then put a file in config/initializers with these contents:</p>
<pre>
module ActiveRecord
  module Acts
    module Versioned
      def acts_as_paranoid_versioned(options = {})
        acts_as_paranoid
        acts_as_versioned options

        # Override the destroy method. We want deleted records to end up in the versioned table,
        # not in the non-versioned table.
        self.class_eval do
          def destroy()
            with_transaction_returning_status do
              run_callbacks :destroy do
                # call the acts_as_paranoid delete function
                self.class.delete_all(:id => self.id)

                # get the 'deleted' object
                tmp = self.class.unscoped.find(id)

                # run it through the equivalent of acts_as_versioned's
                # save_version(). We used to call that function but it is a
                # noop when @saving_version is not set. That only gets done in
                # a protected function set_new_version(). Easier to just
                # replicate the meat of the save_version() function here.
                rev = tmp.class.versioned_class.new
                clone_versioned_model(tmp, rev)
                rev.send("#{tmp.class.version_column}=", send(tmp.class.version_column))
                rev.send("#{tmp.class.versioned_foreign_key}=", id)
                rev.save

                # and finally really destroy the original
                self.class.delete_all!(:id => self.id)
              end
            end
          end
        end

        # protect the versioned model
        self.versioned_class.class_eval do
          def self.delete_all(conditions = nil); return; end
        end
      end
    end
  end
end
</pre>
<p>I wonder if there is a more elegant way to achieve this&#8230;</p>
<p>Note: code updated at 2011-05-28 to make sure :dependent => :destroy on has_many associations does the right thing.</p>
]]></content:encoded>
			<wfw:commentRss>https://ward.vandewege.net/blog/2011/04/acts_as_paranoid-and-acts_as_versioned-on-rails-3/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>monit, mongrel_rails and ENV[&quot;HOME&quot;]</title>
		<link>https://ward.vandewege.net/blog/2009/06/monit-mongrel_rails-and-envhome/</link>
		<comments>https://ward.vandewege.net/blog/2009/06/monit-mongrel_rails-and-envhome/#comments</comments>
		<pubDate>Sun, 28 Jun 2009 14:46:20 +0000</pubDate>
		<dc:creator><![CDATA[ward]]></dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[ENV["HOME"]]]></category>
		<category><![CDATA[gem]]></category>
		<category><![CDATA[mongrel]]></category>
		<category><![CDATA[mongrel_rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[rubyforge]]></category>

		<guid isPermaLink="false">http://ward.vandewege.net/blog/?p=469</guid>
		<description><![CDATA[So your mongrels are humming along happily and you have monit monitoring them with a definition like this: check process mongrel_8010 with pidfile /path/to/current/log/mongrel.8010.pid start program = "/usr/bin/mongrel_rails cluster::start -C /path/to/current/config/mongrel_cluster.yml --clean --only 8010" stop program = "/usr/bin/mongrel_rails cluster::stop -C &#8230; <a href="https://ward.vandewege.net/blog/2009/06/monit-mongrel_rails-and-envhome/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>So your mongrels are humming along happily and you have monit monitoring them with a definition like this:</p>
<pre>
check process mongrel_8010 with pidfile /path/to/current/log/mongrel.8010.pid
  start program = "/usr/bin/mongrel_rails cluster::start -C /path/to/current/config/mongrel_cluster.yml --clean --only 8010"
  stop program = "/usr/bin/mongrel_rails cluster::stop -C /path/to/current/config/mongrel_cluster.yml --clean --only 8010"

  if failed host 127.0.0.1 port 8010
    with timeout 10 seconds
    then restart

  if totalmem > 128 Mb then restart
  if cpu is greater than 60% for 2 cycles then alert
  if 3 restarts within 5 cycles then timeout
  group mongrel
</pre>
<p>The start/stop commands work perfectly from the command line, but somehow not when monit&#8217;s calling them. Sure enough, you find this in the mongrel.8010.log file:</p>
<pre>
/usr/lib/ruby/gems/1.8/gems/rubyforge-1.0.3/lib/rubyforge.rb:15:in `expand_path': couldn't find HOME environment -- expanding `~' (ArgumentError)
</pre>
<p>The line in question is</p>
<pre>
  HOME        = ENV["HOME"] || ENV["HOMEPATH"] || File::expand_path("~")
</pre>
<p>Monit does not set a HOME environment variable, nor HOMEPATH.</p>
<p>The documentation for File::expand_path says:</p>
<pre>
Converts a pathname to an absolute pathname. Relative paths are referenced from the 
current working directory of the process unless dir_string is given, in which case it 
will be used as the starting point. The given pathname may start with a ``~â€™â€™, which 
expands to the process ownerâ€˜s home directory (the environment variable HOME must 
be set correctly). ``~userâ€™â€™ expands to the named userâ€˜s home directory. 
</pre>
<p>Ouch. So if HOME is not set, File::expand_path(&#8220;~&#8221;) is guaranteed to fail. That&#8217;s a bug in the rubyforge gem I think.</p>
<p>I worked around this by setting ENV["HOME"] to a fallback value before the</p>
<pre>
require 'rubygems'
</pre>
<p>line in /usr/bin/mongrel_rails.</p>
<p>I <a href="http://rubyforge.org/tracker/index.php?func=detail&#038;aid=26447&#038;group_id=1024&#038;atid=4025">filed a bug</a>. It took me a while to figure out that the rubyforge gem is part of the <a href="http://rubyforge.org/projects/codeforpeople/">codeforpeople</a> project on <a href="http://rubyforge.org">rubyforge</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://ward.vandewege.net/blog/2009/06/monit-mongrel_rails-and-envhome/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>on the importance of gem cleanup</title>
		<link>https://ward.vandewege.net/blog/2009/06/on-the-importance-of-gem-cleanup/</link>
		<comments>https://ward.vandewege.net/blog/2009/06/on-the-importance-of-gem-cleanup/#comments</comments>
		<pubDate>Tue, 16 Jun 2009 16:35:01 +0000</pubDate>
		<dc:creator><![CDATA[ward]]></dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Sysadmin]]></category>

		<guid isPermaLink="false">http://ward.vandewege.net/blog/?p=448</guid>
		<description><![CDATA[I have a monit config that tries to stop/start mongrel instances like this: start program = "/usr/bin/mongrel_rails cluster::start -C path-to-mongrel_cluster.yml --clean --only PORT" stop program = "/usr/bin/mongrel_rails cluster::stop -C path-to-mongrel_cluster.yml --clean --only PORT" I have the latest mongrel_cluster gem installed &#8230; <a href="https://ward.vandewege.net/blog/2009/06/on-the-importance-of-gem-cleanup/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I have a monit config that tries to stop/start mongrel instances like this:</p>
<pre>
  start program = "/usr/bin/mongrel_rails cluster::start -C path-to-mongrel_cluster.yml --clean --only PORT"
  stop program = "/usr/bin/mongrel_rails cluster::stop -C path-to-mongrel_cluster.yml --clean --only PORT"
</pre>
<p>I have the latest mongrel_cluster gem installed (1.0.5), and yet mongrel_rails kept throwing errors about &#8211;clean and &#8211;only:</p>
<pre>
invalid option: --clean for command 'cluster::start'
invalid option: --only for command 'cluster::start'
</pre>
<p>Turns out I had an older mongrel_cluster gem installed as well:</p>
<pre>
$ sudo gem cleanup mongrel_cluster
Cleaning up installed gems...
:0:Warning: Gem::SourceIndex#search support for Regexp patterns is deprecated
Attempting to uninstall mongrel_cluster-0.2.1
Successfully uninstalled mongrel_cluster-0.2.1
Clean Up Complete
</pre>
<p>After running gem cleanup, the mongrel_rails commands above started working.</p>
<p>This kind of code behaviour irks me &#8211; it&#8217;s not intuitive. It does not help that &#8216;gem list&#8217; suggests that having multiple versions of a gem installed is not a problem &#8211; and it usually is not. I guess the mongrel_cluster gem is an exception. File this one under &#8216;good to know&#8217;&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>https://ward.vandewege.net/blog/2009/06/on-the-importance-of-gem-cleanup/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>rails, mongrel and mysterious gpgme errors</title>
		<link>https://ward.vandewege.net/blog/2008/12/rails-mongrel-and-mysterious-gpgme-errors/</link>
		<comments>https://ward.vandewege.net/blog/2008/12/rails-mongrel-and-mysterious-gpgme-errors/#comments</comments>
		<pubDate>Mon, 08 Dec 2008 17:04:11 +0000</pubDate>
		<dc:creator><![CDATA[ward]]></dc:creator>
				<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://ward.vandewege.net/blog/?p=312</guid>
		<description><![CDATA[Mongrel changes its user and group id to the user you specify when started as another user (say, root). However, it does not change the environment variables from the user it was started as. In particular, ENV["USER"] and ENV["HOME"] remain &#8230; <a href="https://ward.vandewege.net/blog/2008/12/rails-mongrel-and-mysterious-gpgme-errors/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Mongrel changes its user and group id to the user you specify when started as another user (say, root).</p>
<p>However, it does not change the environment variables from the user it was started as. In particular, ENV["USER"] and ENV["HOME"] remain set to, say, &#8216;root&#8217; and &#8216;/root&#8217; respectively.</p>
<p>If you then try to use the ruby gpgme wrappers you&#8217;ll run into strange errors. No Ruby exceptions are triggered, but things go wrong in the gpgme_n C wrapper code. From there, gpg is called as the mongrel user, but with environment variables pointing to root&#8217;s home directory. Ouch.</p>
<p>Of course you won&#8217;t see the problem in development mode (because typically there you run mongrel as the user you are working as).</p>
<p>The solution is simple: force those two variables in your environment.rb file to the correct values for the user you are running as, but not for development mode.</p>
]]></content:encoded>
			<wfw:commentRss>https://ward.vandewege.net/blog/2008/12/rails-mongrel-and-mysterious-gpgme-errors/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>acts_as_paranoid and acts_as_versioned</title>
		<link>https://ward.vandewege.net/blog/2007/02/acts_as_paranoid-and-acts_as_versioned/</link>
		<comments>https://ward.vandewege.net/blog/2007/02/acts_as_paranoid-and-acts_as_versioned/#comments</comments>
		<pubDate>Tue, 27 Feb 2007 22:20:44 +0000</pubDate>
		<dc:creator><![CDATA[ward]]></dc:creator>
				<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://ward.vandewege.net/blog/2007/02/27/116/</guid>
		<description><![CDATA[So you&#8217;re writing a web-based application and you want journalling: when database records change, you want to keep track of the changes so that you have an audit trail. There are many ways to do this. If your application is &#8230; <a href="https://ward.vandewege.net/blog/2007/02/acts_as_paranoid-and-acts_as_versioned/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>So you&#8217;re writing a web-based application and you want journalling: when database records change, you want to keep track of the changes so that you have an audit trail. There are many ways to do this. If your application is going to be dealing with a lot of data, it&#8217;s best to have a separate &#8216;versions&#8217; table for each table, where you store the old versions of your records.A couple of plugins for <a href="http://rubyonrails.org">Rails</a> exist to make this easier. The <a href="http://wiki.rubyonrails.org/rails/pages/ActsAsVersioned">acts_as_versioned plugin</a> deals with journalling for updates to records. It does not journal deletes &#8211; that&#8217;s where <a href="http://ar-paranoid.rubyforge.org/">acts_as_paranoid</a> comes in. That plugin will put a timestamp in the deleted_at column rather than delete the record, and it overrides the various find methods to ignore records with a non-null deleted_at column.</p>
<p>The 2 plugins don&#8217;t work together all that well without some modification, as described by Flinn Mueller <a href="http://www.actsasflinn.com/articles/2007/02/15/acts_as_paranoid_versioned-or-acts_as_versioned-acts_as_paranoid">here</a>.</p>
<p>His solution solves part of the problem &#8211; deleting a record no longer deletes the versioned history of the record. But it still leaves the original record in the main table, with a deleted_at timestamp. I want to move that &#8216;deleted&#8217; record into the versions table, with accurate deleted_at timestamp.</p>
<p>Here&#8217;s how I modified Flinn&#8217;s code to do that:</p>
<pre>
<code>
module ActiveRecord
  module Acts
    module Versioned
      module ClassMethods
        def acts_as_paranoid_versioned(options = {})
          acts_as_paranoid
          acts_as_versioned options

          # Override the destroy method. We want deleted records to end up in the versioned table,
          # not in the non-versioned table.
          self.class_eval do
            def destroy()
              transaction {
                destroy_with_callbacks                 # call the acts_as_paranoid delete function
                tmp = self.class.find_with_deleted(id) # get the 'deleted' object
                tmp.save_version()                     # run it through acts_as_versioned's save_version()
                tmp.destroy_without_callbacks!         # and finally really destroy the original
              }
            end
          end

          # protect the versioned model
          self.versioned_class.class_eval do
            def self.delete_all(conditions = nil); return; end
          end
        end
      end
    end
  end
end
</code>
</pre>
<p>This code goes in config/environment.rb. As you can see it&#8217;s a bit of a hack, but it works. If you have suggestions to do this more elegantly, by all means leave a comment. </p>
<p>I think it&#8217;s time someone merges acts_as_paranoid into acts_as_versioned. Maybe I&#8217;ll look at that one day when I have more time &#8211; for now this will do.</p>
]]></content:encoded>
			<wfw:commentRss>https://ward.vandewege.net/blog/2007/02/acts_as_paranoid-and-acts_as_versioned/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
