Basics that I'm getting stuck on.

23 views
Skip to first unread message

TylerWeir

unread,
Dec 29, 2007, 9:20:51 PM12/29/07
to liftweb
Hey all,

I'm getting stuck on some basics and I thought rather than spend more
time looking through code and playing the trial and error game, I'll
ask for clarification. I'm positive that what I'm doing is *not* best
practice. :) I'll put anything that comes from this on the wiki as
well.

1) SImply spilling the contents of a model object as read only - is
there a better way than binding each of the members, something like a
read-only toForm? I looked at asHtml, but it appears to be for a
single member, not an object.

2) toForm is great for many cases, but if I would like to offer a
<select> that has a list of all the ForeignKeyed members, then I'm not
sure how to build the form, as toForm does not magically create the
<select> for me.

For example, I have a Client Model object and a Project Model object.
One of the fields in Project is a foreign key to Client. toForm will
create an input field for the ClientID foreign key, but I want a
<select>.

I'm using the sites/example as my basis for my project, so most of my
code spelunking is from that app.

Thanks,
Tyler


David Pollak

unread,
Dec 31, 2007, 11:34:50 AM12/31/07
to lif...@googlegroups.com
On Dec 29, 2007 6:20 PM, TylerWeir <tyler...@gmail.com> wrote:

Hey all,

I'm getting stuck on some basics and I thought rather than spend more
time looking through code and playing the trial and error game, I'll
ask for clarification.  I'm positive that what I'm doing is *not* best
practice.  :)  I'll put anything that comes from this on the wiki as
well.

1) SImply spilling the contents of a model object as read only - is
there a better way than binding each of the members, something like a
read-only toForm?  I looked at asHtml, but it appears to be for a
single member, not an object.

Mapper.asHtml dumps the contents of a model object as XHTML.
 


2) toForm is great for many cases, but if I would like to offer a
<select> that has a list of all the ForeignKeyed members, then I'm not
sure how to build the form, as toForm does not magically create the
<select> for me.

This is intentional because there's no way to know the scope of what to select for a foreign key.  I'll noodle a little on this and make a code change that allows the "right thing" (tm) to happen for foreign keys.

You can also implement your own toForm on the element that does what you want it to.
 


For example, I have a Client Model object and a Project Model object.
One of the fields in Project is a foreign key to Client.  toForm will
create an input field for the ClientID foreign key, but I want a
<select>.

I'm using the sites/example as my basis for my project, so most of my
code spelunking is from that app.

Thanks for the questions and please keep them coming.

Bonus points for doing a diary on the liftweb.net wiki!

Thanks and Happy New Year!

David
 


Thanks,
Tyler




--
lift, the secure, simple, powerful web framework http://liftweb.net
Collaborative Task Management http://much4.us

David Pollak

unread,
Dec 31, 2007, 2:10:52 PM12/31/07
to lif...@googlegroups.com
Tyler,

Okay... in your ForeignKey field, override:
def validSelectValues: Can[List[(KeyType, String)]] = Empty

To return a list of valid values for the FK.  The toForm method will generate a select on the values.

A couple of things about the implementation:
  • It hides the value of KeyType from the select so there are just opaque ids that are sent to the browser so there's no security problem with people being exposed to the primary keys
  • parameter tampering is improbably (because of the opaque keys)
Enjoy.

Thanks,

David

TylerWeir

unread,
Dec 31, 2007, 3:27:14 PM12/31/07
to liftweb
I'll try this now.

Thanks Dave!

On Dec 31, 2:10 pm, "David Pollak" <feeder.of.the.be...@gmail.com>
wrote:
> Tyler,
>
> Okay... in your ForeignKey field, override:
> def validSelectValues: Can[List[(KeyType, String)]] = Empty
>
> To return a list of valid values for the FK.  The toForm method will
> generate a select on the values.
>
> A couple of things about the implementation:
>
>    - It hides the value of KeyType from the select so there are just
>    opaque ids that are sent to the browser so there's no security problem with
>    people being exposed to the primary keys
>    - parameter tampering is improbably (because of the opaque keys)
>
> Enjoy.
>
> Thanks,
>
> David
>
> On 12/31/07, David Pollak <feeder.of.the.be...@gmail.com> wrote:
> > Collaborative Task Managementhttp://much4.us

TylerWeir

unread,
Jan 1, 2008, 11:22:08 AM1/1/08
to liftweb
Hey Dave,

So I've got things hooked up like so:

<tt>
object clientID extends MappedLongForeignKey(this, Client)
{
override def validSelectValues: Can[List[(Long, String)]] = Empty
}
</tt>

And if I try to add a new record or edit I get "Can't Change" for all
MappedForiegnKeys.

I hopped into the Mapper code to see what was going on. But I've got
nothing so far. Should I be supplying the valid values or is that
done for me?

Thanks,
Ty

David Pollak

unread,
Jan 1, 2008, 12:15:28 PM1/1/08
to lif...@googlegroups.com
Tyler,

If you return empty, then there's nothing to display and you get the
"Can't Change" element.

If you want to return a list, you would do something like:
override def validSelectValues: Can[List[(Long, String)]] = Full
(Clients.findAll.map(c => (c.id.is, c.name.is)))

Thanks,

David

--
David Pollak
http://blog.lostlake.org

TylerWeir

unread,
Jan 1, 2008, 1:26:58 PM1/1/08
to liftweb
Gah, ok, I was being a bonehead.

Thanks... again. :)

Ty

TylerWeir

unread,
Jan 15, 2008, 9:03:24 PM1/15/08
to liftweb
A followup:

Now that this is working well, I'd like to automatically set the
correct User, right now I'm doing this, crazy or sane?

object userID extends MappedLongForeignKey(this, User)
{
override def validSelectValues: Can[List[(Long, String)]] =
Full(User.findAll(By(User.id, User.currentUser.openOr(new
User).id)).map(c => (c.id.is, c.firstName + " " + c.lastName.is)))
}

It's working, but is it right?

Thanks,
Tyler
> > >>>>> I'm getting stuck on somebasicsand I thought rather than

David Pollak

unread,
Jan 15, 2008, 10:46:16 PM1/15/08
to lif...@googlegroups.com
On Jan 15, 2008 6:03 PM, TylerWeir <tyler...@gmail.com> wrote:

A followup:

Now that this is working well, I'd like to automatically set the
correct User, right now I'm doing this, crazy or sane?

 object userID extends MappedLongForeignKey(this, User)
 {
               override def validSelectValues: Can[List[(Long, String)]] =
Full(User.findAll(By(User.id, User.currentUser.openOr(new
User).id)).map(c => ( c.id.is, c.firstName + " " + c.lastName.is)))

}

It's working, but is it right?
I don't think so.

Why are you finding by the current user-id?

Can you describe in English what the list is supposed to contain?
 


Thanks,
Tyler


On Jan 1, 1:26pm, TylerWeir <tyler.w...@gmail.com> wrote:
> Gah, ok, I was being a bonehead.
>
> Thanks... again. :)
>
> Ty
>
> David Pollak wrote:
> > Tyler,
>
> > If you return empty, then there's nothing to display and you get the
> > "Can't Change" element.
>
> > If you want to return a list, you would do something like:
> > override def validSelectValues: Can[List[(Long, String)]] = Full
> > (Clients.findAll.map(c => ( c.id.is, c.name.is)))



--

TylerWeir

unread,
Jan 16, 2008, 7:28:56 AM1/16/08
to liftweb
I want the list to only contain the logged in user, otherwise the
logged in user can create a record for a different user.

I shouldn't even be searching for the user... oy, programming at night
while sick is proving to be detrimental.

Tyler


On Jan 15, 10:46 pm, "David Pollak" <feeder.of.the.be...@gmail.com>
wrote:
> On Jan 15, 2008 6:03 PM, TylerWeir <tyler.w...@gmail.com> wrote:
>
>
>
> > A followup:
>
> > Now that this is working well, I'd like to automatically set the
> > correct User, right now I'm doing this, crazy or sane?
>
> >  object userID extends MappedLongForeignKey(this, User)
> >  {
> >                override def validSelectValues: Can[List[(Long, String)]] =
> > Full(User.findAll(By(User.id, User.currentUser.openOr(new
> > User).id)).map(c => (c.id.is, c.firstName + " " + c.lastName.is)))
> > }
>
> > It's working, but is it right?
>
> I don't think so.
>
> Why are you finding by the current user-id?
>
> Can you describe in English what the list is supposed to contain?
>
>
>
>
>
> > Thanks,
> > Tyler
>
> > On Jan 1, 1:26pm, TylerWeir <tyler.w...@gmail.com> wrote:
> > > Gah, ok, I was being a bonehead.
>
> > > Thanks... again. :)
>
> > > Ty
>
> > > David Pollak wrote:
> > > > Tyler,
>
> > > > If you return empty, then there's nothing to display and you get the
> > > > "Can't Change" element.
>
> > > > If you want to return a list, you would do something like:
> > > > override def validSelectValues: Can[List[(Long, String)]] = Full
> > > > (Clients.findAll.map(c => (c.id.is, c.name.is)))

David Pollak

unread,
Jan 16, 2008, 11:33:30 AM1/16/08
to lif...@googlegroups.com
Tyler,


TylerWeir wrote:
I want the list to only contain the logged in user, otherwise the
logged in user can create a record for a different user.
  
I'm being dense... If there's a user logged in, the list should only contain that user, otherwise the list should contain... ?

TylerWeir

unread,
Jan 16, 2008, 12:47:22 PM1/16/08
to liftweb
Sorry, it's my explanations.

The user field is a foreign key to the User table, but that value for
should only ever be the user that is logged in.

So rather than offer a list of all the users in the select, I wanted
to have just the logged in user.

Thanks,
Ty

Steve Jenson

unread,
Jan 16, 2008, 12:57:11 PM1/16/08
to lif...@googlegroups.com
[WARNING] Potentially dumb question: Why show if it can't be changed?
It seems like a select with only ever one element in it.

always prefacing statements with log4j categories,
Steve

TylerWeir

unread,
Jan 16, 2008, 1:13:26 PM1/16/08
to liftweb
[WARNING] I lack understanding: toForm spills every field, so this was
a way to solve that.

I suppose the other way is to create the Form myself and not use
toForm.

Ty

On Jan 16, 12:57 pm, "Steve Jenson" <ste...@gmail.com> wrote:
> [WARNING] Potentially dumb question: Why show if it can't be changed?
> It seems like a select with only ever one element in it.
>
> always prefacing statements with log4j categories,
> Steve
>

David Pollak

unread,
Jan 16, 2008, 1:20:26 PM1/16/08
to lif...@googlegroups.com
Tyler,

You can override the toForm method in the field and return any NodeSeq you want.

If you need, I can change the signature in toForm to return Can[NodeSeq] and the whole field will be omitted if the Can is not Full.

What say you?

Thanks,

David

TylerWeir

unread,
Jan 16, 2008, 1:42:11 PM1/16/08
to liftweb
"You can override the toForm method in the field and return any
NodeSeq you want. "

Awesome, I didn't know that. Let me try that tonight, hopefully
sooner.

Thanks Dave (again)
Ty
Reply all
Reply to author
Forward
0 new messages