best way to add "created_by" entries to all tables???

I want to automate somewhat the addition of created_by/updated_by fields on my models (i.e. to include username). What's the best/recommended way to do this? Would it be to:

A simple way would be to add records via your user models. Take a users/articles relationship. Article belongs_to User, User has_many Articles.

When you create the article, if you do it like this:

@user.articles.create(params)

then your articles are automatically linked to the creating user.

The problem with using before filters in the models to do this is that you would some how need to get hold of the user's name - likely to be via the session like this:

user = User.find(params[:user_id])

But including that in the model would be breaking the whole MVC thing.

If you have a small amount of models, it's probably easier to just manually specify the users:

article.created_by = @user.name

or

article.updated_by = @user.name

As you would only be updating/creating in one place, it's not a huge amount of code.

Any other thoughts on this?

Steve

I could take this approach Steve (of adding “article.created_by = @user.name” to each model) and then extend this via customising my generator for model creation perhaps. This way whenever I generate a model it would have this added automatically. I guess it’s a slightly different way of adhering to DRY (don’t repeat yourself).

I would still be interesting in following some sort of “extend the base class” approach to be really DRY compliant :). Anyone have any comments on this option, i.e. this would mean somehow
extending “ActiveRecord::Base” no doubt?

Tks

Hello Greg,
    Urm, okay, stupid question, but, why not take the -exact- same route
as the 'timestamp.rb' file contained in the activerecord gem ?
Basically, it allows you to switch on timestamping (and thus populates
the created_at field) or switch it off on a per model basis. I dare say
that you could look at the 60* or so lines, and get it to do what you
want to do. This way would definitely be more DRY, and if you do it
right, you could include it for inclusion into Rails or at least make it
a nice little 'plugin' or some such :wink:

    Jst a thought.
    Regards
    Stef
(* and out of those 60 lines, only half or less are actually -code- :wink:

Greg H wrote:

I would still be interesting in following some sort of "extend the base class" approach to be really DRY compliant :). Anyone have any comments on this option, i.e. this would mean somehow extending "ActiveRecord::Base" no doubt?

It's easy to extend activerecord but I can't really see how this will help your situation. You'll still need to know *who* the user is - that information will either need to be passed during the method call or obtained from the session (which would break MVC).

How DRY the method I mentioned is depends on how many models you have to update with this information.

If you're interested in how you extend classes, have a look at http://www.juixe.com/techknow/index.php/2006/06/18/rails-plugin-tutorial/ for details on how to write plugins.

Steve

thanks Steve - I’ll look this up. BTW - I already have a process for getting hold of the userid (I looked up how some of the plugins did it)

Actually, what about this:

Option 1

a) create a “MyActiveRecordBase” class which extends “ActiveRecord:Base”. Place all the custom things you want in here.

b) for all your own model classes extend from “MyActiveRecordBase”
c) modify your model generators to align with this for ease

or

Option 2

I thought I read it was possible to just define your own version of a class (e.g. “ActiveRecord:Base”) and put the methods you want to override. In this case it would be more adding in class calls like “before_create :generic_fields” however, so I’m not sure if this would work?

or

Option 3

Use of the “extend” method as per the plugin tutorial that Stephen suggested:

http://www.juixe.com/techknow/index.php/2006/06/18/rails-plugin-tutorial/

Any coments on the pro’s/con’s of the above? Or are all just as good as each other?

Cheers

Any coments on the pro's/con's of the above? Or are all just as good as each other?

I'll reply again :0)

Option 1 - Not cool because it's not really using the power of ruby to dynamically extend classes. It also makes it difficult to add this functionality to existing models.

Option 2 - This is true - Ruby classes are never 'closed' so you can just happily open them up and start adding more methods.

However, this is effectively the same as:

Option 3 - which will allow you add and override methods dynamically across specified models. You create the plugin that loads when the application starts. In your models, you simply add the call to use this plugin:

class MyModel < ActiveRecord::Base
   track_users
end

Yeah, you have to add one line of code to models that require tracking, but that's a good thing - I wouldn't have thought that you really want *all* of your models tracked.

The other benefit is that the functionality is nice and encapsulated, ready to use in other apps and share with your friends!

The actual extension itself should be pretty easy:

def before_create
   created_by = however_youre_doing_this
   super
end

Hope that helps

Steve

thanks Steve :slight_smile:

Just briefly:

a) with the “before_create” example method you just posted, do you actually need to call super at the end? I haven’t tested, however I would have thought if rails provides a “before_create” method you wouldn’t have to do this?

b) re my option 2 - what I meant to imply was an option where you don’t touch the rails class itself, but put your own copy of with the same file name into your application - I thought I saw somewhere you could do this and your local copy would override the real copy with any methods from your local copy - am I dreaming this up? Was it just rails “Engines” that supports this and not rails itself?

Tks

a) with the "before_create" example method you just posted, do you actually need to call super at the end? I haven't tested, however I would have thought if rails provides a "before_create" method you wouldn't have to do this?

super just calls the same method but in the super class. As you're overriding the super's method, you may need to call any additionally defined hooks.

b) re my option 2 - what I meant to imply was an option where you don't touch the rails class itself, but put your own copy of with the same file name into your application - I thought I saw somewhere you could do this and your local copy would override the real copy with any methods from your local copy - am I dreaming this up? Was it just rails "Engines" that supports this and not rails itself?

Yeah that's a ruby feature. You can just drop a file in lib/, include it in your environment.rb and just open up any existing class:

for example, string.rb:

class String
   def i_say
     "Steve says: " << self
   end
end

Then you would be able to do this:

my_string = "Hello"
my_string.i_say -> "Steve says: Hello"

Excuse the weird example, but I hope it explains it :0)

You can do this just as easily with the rails classes like activerecord, but it's not as neat a solution as using the existing plugins system.

Steve

thanks Steve for clearing that up for me :slight_smile:

Hey, if you’re keen to reply to one more of my posts, I’m stuck on one aspect of the filters. My post is at the URL below…still no replies for the moment…Tks again :slight_smile:

http://www.ruby-forum.com/topic/80742#new