[jifty-devel] Questions about Jifty features

Andrew Sterling Hanenkamp sterling at hanenkamp.com
Thu Aug 16 22:24:55 EDT 2007


I'm not by any means the expert on Jifty, but I've given my thoughts below.

On 8/14/07, Stéphane Alnet <stephane at carrierclass.net> wrote:
>
> Hello,
>
> Sorry for the long email. I'm new to Jifty and wanted to evaluate the
> complexity of implementing some of the things I need in my application
> before "making the move". I especially need:
>
> (1) Adding constraints on SQL queries:
>
>     I need to be able to filter the display and restrict the insertion
> of the content of all Models based on which "group" a user belongs to
> (groups are stored in the Model alongside the users). Some key SQL
> tables in my model contain a "group_id/owner_id" pointer to the group
> that owns subsets of records (it doesn't make sense in the model to
> have all tables have an owning "group" because external dependencies
> dictate what can be viewed/modified from that selected set of SQL
> tables). I already have code that generates SQL fragments on-the-fly
> to do cross-table constraints (for example, user A can see records
> WHERE external_id IN (SELECT id FROM external_table WHERE group IN
> (SELECT group FROM group_user WHERE user = $user)), etc.), but I'm
> fine with using something better inside Jifty.
>
>     Is this what RightsFrom implements?
>     RightsFrom seems to only care about "users", not "groups", how
> should I extend this cleanly to support "groups"?


I'm not precisely clear about what RightsFrom does. To quote the comments in
the code "this card is bloody hard to follow. it's my fault. --jesse" I
believe the intention is to basically let you do to the current record
whatever you can do to the linked record. However, Jesse or someone with a
longer history with Jifty can probably give you more detail.

The key to determining whether you can do something in Jifty is defining a
current_user_can() method in your models. You can define a common one for
all your models by simply adding a definition to you MyApp::Record class. If
you have a couple different sets you use, you could use additional custom
base classes as well. I'd recommend starting with
Jifty::Manual::AccessControl if you have not already.

I also highly recommend building up some handy shorthand methods in
MyApp::CurrentUser to handle things like testing in_group() and
is_owner_of() to help write your current_user_can() methods.

(2) Implementing changesets:
>
>     I need to provide the ability to do different things which end up
> being basically the same thing:
>     - Undo: must be able to reverse a change that was previously done;
>     - Change Control / Policy reviews: a change done by an actor
> (user) A may be subject to review by another user B (or a chain / set
> of actors);
>     - Timed changes: changes are applied at a given date and time (for
> example for contractual reasons).
>
>     The way I decided to implement this is to define what I call
> "ChangeSet"s which basically record the changes that would have been
> done in the database (which table and columns would have been
> modified, what are the old and new values, etc.), and depending on the
> result to be obtained (simple Undo, Change Control review, timed) will
> (respectively) apply the ChangeSet immediately, after review, or at a
> given time (controlled externally).
>
>     In turn, a "commit" of a changeset generates an INSERT/UPDATE
> using the "new" values in the ChangeSet (for create/modify), or
> marking a record as inactive (for delete). Conversely an Undo
> (reversal) of a changeset involves marking the record inactive (for
> create), generating an UPDATE using the "old" values in the ChangeSet
> (for modify), or marking the record active (for delete); etc.(*)
>
>     To achieve this I need to be able to:
>
>     (a) mark records in the database as active/inactive; only "active"
> records should be visible within Jifty. My understanding is that the
> simplest way to do add such a field is to create a Mixin and use it in
> each model in my application (the mixin basically adds a boolean
> "active" column, ..).
>
>         How would I then filter the records avaible within Jifty?
>         Is there a way to implement this within the mixin (i.e. drop
> the record if "active is not true")?


I can think of one good way. In general, whenever you need to iterate
through a collection of models you do one of two things. You always start by
creating a new collection object and then you either call unlimit() to fetch
all records or call limit() one or more times to limit which records to
fetch.

I would suggest overriding the collection object for the ChangeSet model and
then add a limit_to_active() method to use in place of unlimit(). That would
make it easy and self-documenting without having to type
$collection->limit(column => 'active', value => 0) every time. If you need
this for every class in your application, just throw the limit_to_active()
method into MyApp::Collection and add the active column to a schema into a
mixin included with all your classes (you could even add it to a schema
block in MyApp::Record, but intuition tells me that you rarely need to add a
column to every single model).

    (b) replace the standard create/modify/delete in Jifty by versions
> that implement the ChangeSet mechanism (except for private Jifty
> tables and the changeset tables themselves).
>
>         Would creating appropriate delete(), insert() and
> update_record_value() in MyApp::Handle be sufficient?


Without knowing more about what you're doing here, I'm not sure what to
recommend. There is some work involving records with built-in versioning
being done, but it's in a branch and not finished at this time.

The way it works (last I looked) was to actually store old versions of the
records away in Subversion, but I don't know what state it's in now, how
serious the implementation is, what it's capable of doing to restore old
versions, what the performance characteristics are or anything else. But
there has been some work at handling record revisions as a built-in feature
of Jifty.

I don't know if that's even compatible with your ideas of ChangeSets, but
since I can't answer the question properly, I thought I'd at least let you
know about something that sounds similar. And, I haven't taken the time to
look over what you've put up on google code. :(

(3) Hiding parts of forms based on a form field:
>
>     I need to show different forms based on the value a user selected
> in a field (for example I have a SQL table that store information for
> different types of trunks; the parameters for each class of trunks are
> independent; this is similar in spirit to PostgreSQL's INHERIT
> mechanism). I've seen Jifty::Manual::PageRegions; but I'm not sure how
> to use that kind of technics to bind a field (generated by Jifty based
> on the Model) to showing/hiding a region on the web interface, or
> forcing/disabling the validation of field in the Model.
>
>         What is the proper way of implementing this?


I'm not certain if Jifty supports a way to do this, but adding in the
necessary JavaScript shouldn't be difficult:

// in share/web/static/js/app_behaviour.js
Behaviour.apply({
    'input.argument-my_radio': function(e) {
        e.onclick = function() {
            if (this.value == 'X') { Element.show($('subform-X'));
Element.hide($('subform-Y')); }
            if (this.value == 'Y') { Element.show($('subform-Y'));
Element.hide($('subform-X')); }
        };
    },
    'div.subform': function(e) { Element.hide(e); }
});

I would then wrap those parts of the form in divs marked with "subform-X"
and "subform-Y" IDs and "subform" classes.

If Jifty doesn't already have a way to do this for you, it'd be nifty to
have a subform plugin for this sort of thing.

Anyway, I hope at least some of this has been helpful.

Cheers,
Andrew
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.bestpractical.com/pipermail/jifty-devel/attachments/20070816/8a569be9/attachment.htm


More information about the jifty-devel mailing list