I had mentioned this in the Radiant Core list a little while ago because
I wanted people to test it out before I distributed it more widely, but
I think it’s time to let it loose. Unlike the other extensions I have
released in the last few weeks, I’m not putting this one in the Radiant
repository, but keeping it in my own. It may end up there later,
however.
Before you start using this, let me warn you about a few things. First,
there is very little documentation other that what I have written for
the tags. If you want image resizing (for the thumbnails), make sure
you have RMagick installed. For Win32 this obviously means the full
package that comes with IM. For *nix, OS/X and others, use whatever is
necessary to get it installed, which could be a package manager, or
could be building from source. It can be tricky, so just be warned.
Other than installation, everything else is pretty straightforward.
Just checkout the extension into vendor/extensions, run rake db:migrate:extensions, then start up or restart your server. When you
open a page for editing, cilck the ‘Attachments’ link toward the bottom
to pop up the box for adding attachments.
TODO:
Change the method of deleting attachments to not commit until page is
saved.
Move the ‘minus’ icons up to one icon in the title bar and provide a
way to select attachment boxes with JS/CSS.
I had mentioned this in the Radiant Core list a little while
ago because
I wanted people to test it out before I distributed it more
widely, but
I think it’s time to let it loose. Unlike the other
extensions I have
released in the last few weeks, I’m not putting this one in
the Radiant
repository, but keeping it in my own. It may end up there
later, however.
My extension is a little rougher around the edges than yours at the
moment, but I’m planning on spending Tuesday night fixing that up (and
removing the dependence on my other admin_parts plugin) - it’s currently
much f. In the meantime, could you please give my extension a spin an
make any notes as to what you’d like to see changed to try and bring our
extensions together?
Some differences:
I’ve put the creation of a new asset into a popup window. Uploading of
the asset happens when you submit the popup.
My approach has the advantage that you immediately see the thumbnail of
the image, and also the filename of the image, so that it’s a much
easier thing to explain to people what to put in the <r:attachment
name=“blah”> tags. My approach also keeps attachments around in the case
of a validation problem, and also ensures that the upload of the image
occurs only once. In the popup, I’ve also made Title an attribute of an
attachment. I’m not sure if that’s a good idea or not generally, but I
wanted it for my stuff - I use the title in the title attributes of
images, and it also gives another way to get reference the image.
Regardless of whether title should be included there, using a popup
gives somewhere for more attributes to go (transformation settings?
notes?). One downside of my approach is that an asset uploaded for a
page that is never saved is still going to sit around, but that’s not a
biggy.
I’ve decided that the removal of assets should be another page down -
the attachment gets its own page to edit the metadata (I haven’t checked
this into my svn… ok. I haven’t done it yet.)
I’ve put in a lot more flexibility with image transformation using
FlexImage. This provides a standard mechanism for doing resizing and
prettying up - there needs to be some sort of image transformation
library used. Implementing a transformation requires only dropping a
.flexi file into the views folder. The downside to the approach that
I’ve taken is that image transformation happens at request time and goes
through the radiant cache - This will hopefully not be a problem once I
get get action_cache working (see earlier posts by me), which hopefully
will get done before the end of the month (my webserver wont like me if
I go live without it).
I store the original attachments in their own directory (not just in
public/). I might make these blobs in the db - single thing to backup,
and supports scaling to multiple webservers. The only reason I haven’t
is that the rails logging will log the contents of those blobs in dev
mode, making the logfiles explode. Will probably make this optional.
The urls for assets are referenced by users as sub-urls of the page
that they’re attached to. This allows assets to be added to unpublished
pages on the site and also remain unpublished. Also the urls look nicer.
The downside is that /asset/ anywhere in the site will go through the
asset controller method, but that’s not really a problem as it delegates
back to the page finding mechanism if it doesn’t match an asset.
Okay, got a comment (Not specifically directed at you) – A question too
– Are the plug-ins specific to Mental/Trunk Radiant, or can they be
used on either? and if specific, which is this for? As well, I see
references to a lot of plug-ins; nothing updated on the site though.
Maybe something easier to manage for plug-ins?
When we say ‘extension’ we are specifically referring to the ‘mental’
branch, aka version 0.6-long-before-release-alpha (a technical term
). ‘Plugins’ usually refer to plugins for Rails – add-ons for 0.5.x
take this form most often. Unfortunately, there’s not any good
documentation for either yet.
Okay, got a comment (Not specifically directed at you) – A
question too
– Are the plug-ins specific to Mental/Trunk Radiant, or can they be
used on either? and if specific, which is this for? As well, I see
references to a lot of plug-ins; nothing updated on the site though.
Maybe something easier to manage for plug-ins?
These are extensions - hence, the mental branch (which introduces
radiant extensions). I’m guessing that extensions wont be discussed too
much on the radiant site until mental goes live.
My extension is a little rougher around the edges than yours at the
moment, but I’m planning on spending Tuesday night fixing that up (and
removing the dependence on my other admin_parts plugin) -
Ok. Scratch that. Just re-jigged it a lot. Pulled in a couple of things
from your design and moves to consistently using the word ‘Attachment’.
Hence this is now the PartAttachments extension.
So you’ll need to rename that dir to part_attachments on the way down.
Still depends on the admin_parts extension (same repository), but I’ve
removed the obnoxious bits of the admin_parts extension, so it should
just quietly stay out of the way.
While they seem to tackle the same problem, I think our extensions have
very
different philosophies and can thus probably live separate lives.
Here’s
some of the design decisions I made:
Uploaded files should live in the filesystem where the web server can
serve them efficiently to the client.
Although logically it would be nice to have uploaded files live in a
directory structure related to the page, page urls/slugs can change more
easily than files can be moved. Thus it’s probably better that the
storage
location of files be orthogonal to the page layout.
Pages should be able to easily access the assets/files belonging to
their
parent(s). So, in-page tags that reference an asset also search through
the
parent pages until it is found.
acts_as_attachment has worked well for me in the past, so I’ll use
that
for handling the uploads and file management.
The UI should mimic John’s original comps as closely as possible.
John liked the way Basecamp allowed you to do multiple uploads
(without a
popup), so let’s do that similarly.
I hope this reveals to you why I did certain things and not other
things.
I’ll continue to look through your code to see if there’s anything I can
learn that might enhance page_attachments.
I store the original attachments in their own directory (not just in
public/). I might make these blobs in the db - single thing to backup,
and supports scaling to multiple webservers. The only reason I haven’t
is that the rails logging will log the contents of those blobs in dev
mode, making the logfiles explode. Will probably make this optional.
I haven’t played with either of these extensions yet but I just wanted
to comment on the log file issue expressed above. Would it be easy
enough to just add a “filter_parameter_logging” call to the file field?
That SHOULD reduce the output in the logs to “[FILTERED]”
I think once I get action_cache working 1 & 2 will be a non-issue - if
the assets are stored seperately and then cached efficiently you’ll get
the same performance and also not have the problem of page movement
interfering.
For 3, I’m not really sure I see the need. In my extension, you can get
a parent’s asset by wrapping the <r:attachment> call in an <r:parent> -
I don’t really understand why searching up the tree is necessary. But
this is just a couple of lines in the tags file, so I don’t see it as a
major difference. Can you give me an example of when you’d want this?
acts_as_attachment is fine, but interferes with trying to do 1 & 2.
Also, the image manipulations provided are fairly rudimentary - how easy
is it for other extensions to specify their preferred image
manipulations (for example, all images for articles need to be resized
to by 200x200 and also need to be thumbnailed at 50x50?)
5 & 6 - I guess that’s just a difference in interface design - I think
the popup guides the user better, but if that was the only point of
difference it would be easy enough to extend the extension with an extra
interface modification extension (well, once the view load order problem
is fixed anyway).
I’d really like us to get a unified data model going - I’ll try and get
work done with action_cache this week - it should be just as efficient
as the acts_as_attachment method (well not quite as efficient, but
little enough difference to matter), and it really does give us a lot
more scope with what the extension can do.
While they seem to tackle the same problem, I think our
extensions have very different philosophies and can thus probably live
separate lives. Here’s some of the design decisions I made:
Uploaded files should live in the filesystem where the web
server can serve them efficiently to the client.
Although logically it would be nice to have uploaded files
live in a directory structure related to the page, page urls/slugs can
change more easily than files can be moved. Thus it’s probably better
that the storage location of files be orthogonal to the page layout.
Pages should be able to easily access the assets/files
belonging to their parent(s). So, in-page tags that reference an asset
also search through the parent pages until it is found.
acts_as_attachment has worked well for me in the past, so
I’ll use that for handling the uploads and file management.
The UI should mimic John’s original comps as closely as
possible.
John liked the way Basecamp allowed you to do multiple
uploads (without a popup), so let’s do that similarly.
I hope this reveals to you why I did certain things and not
other things. I’ll continue to look through your code to see if there’s
anything I can learn that might enhance page_attachments.
I see you mention that your extension uses FlexImage, is this reflected
in
your svn repository? The only reference I can see is that you have the
following in your attachment model:
def self.flex_available
Object.const_defined? :FlexImage
end
Is FlexImage used within your extension at the moment? Maybe I’m just
getting confused as to how you’re using it, as I can’t see any benefits
over
the usual acts_as_attachment/RMagick combination.
A statement in general about extensions: If your extension has any
dependencies, it’s best to include them in the lib/ directory of the
extension. That way you can avoid any ‘dependency hell’. The
exception, of
course, is gems and other libraries like RMagick that are potentially
system-specific (i.e. binary) or require installation. The thing I
liked
about acts_as_attachment is that it still works even if you don’t have
RMagick.
You’re not crazy. With the way the loading mechanism works, you don’t
have
to ‘require’ them, just use them. As long as the files are named in the
standard Rails way (name of the class/module underscored), they will be
loaded. Namespaced modules and classes of course should be put under
directories that have the aforementioned convention.
The problem you likely had with FeedParser is that the underscored form
of
that name is feed_parser, so the file it would search for is
feed_parser.rb. The same would occur with its sub-modules/classes -
feed_parser/text_converters.rb.
Getting FeedParser for Ruby to work out of the extension/lib
directory for the RSS extension proved all but impossible as far as I
could tell. All the same stands true for the Akismet library in
commentable too. I just don’t think that the my_extension/lib is in
the path though I know it was in the plugins/behavior world and
thought it worked earlier when playing with extensions:
e.g.
For RssReader the FeedParser module was setup such that it had a
there is a file at lib/feedparser.rb and also a directory including
some of it’s depedencies which it explicitely references using paths
relative from the lib directory (e.g. require ‘feedparser/
textconverters’).
I tried this setup as well as moving the supporting files out of the
feedparser directory and directly into lib themselves (changing the
relative paths in the require statements).
After trying any number of tricks including giving the requires
absolute paths from Radiant’s root (a la "vendor/extensions/
rss_reader/lib/feedparser’)
Everything I tried always got me the same error from mongrel on
starting the server:
/Applications/Locomotive2/Bundles/standardRailsSept2006.locobundle/
powerpc/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in
`gem_original_require’: no such file to load – feedparser
(MissingSourceFile)
…
Any Page types I’ve put in lib do get loaded so this is fishy to me.
I hope I’m missing something, but as far as I can tell files in
extension/lib are not reliably getting loaded?
extension_loader.rb has this:
def discover_extensions
config.extension_paths.map do |path|
Dir.glob("#{path}/*").sort.select { |f| File.directory?
(f) }.map do |ext_path|
load_paths = %w(lib app/models app/controllers app/
helpers).map { |p| “#{ext_path}/#{p}” }
load_paths << ext_path
load_paths.each { |p| config.load_paths << p }
config.controller_paths << “#{ext_path}/app/controllers”
config.view_paths << “#{ext_path}/app/views” @extension_roots << ext_path
end
end.flatten
end
Which looks to me like it should be setting-up the necessary load
paths to make things go…
(Sean re. extension/lib autoloads – thanks, that makes perfect sense
though I’m still not sure I’m not crazy
Is there any magic way to add a javascript file reference to the
header of my site pages without doing the obvious and just dropping
it in my Layout?
I’m currently writing a large extension which will be js heavy and
I’d like to make it as clean as possible. Install and go.
I walked through the site_controller through parsing code this
morning again and don’t see anything there, so, I guess I’d like to
just confirm that I didn’t miss something.
Well, depends on whether you’re talking about a Radiant layout or a
Rails
layout (i.e. in the views/layouts directory).
I might suggest when your extension activates, do some creation of the
appropriate javascript files (if they don’t exist), either in the public
directory or as pages in Radiant. I have an idea brewing in the back of
my
head about copying extension assets on installation or on demand, but
I’ll
probably want to talk it over with the rest of the team.
Now if you’re just talking about the admin interface, you can write
Javascript code directly into the layout with the content_for block (I
forget exactly what the section is, but look at
app/views/admin/page/page.rhtml for an idea.) If you don’t want it in
your
template, just put it in a partial where it’s easier to update and
render
that partial inside the block.
Well, that sorta answers the question. I need to look web standards
and js a bit. I definately want to manage the js file as a file and
not as a page or snippet. I also think I’ll really need it to load
within but that’s a web standards question. If it still
works and validates and I can load the file in as body then that’s
great. The file loads everything-up on window.onload anyhow so it
won’t even try to load until after the HTML is done.
I did see those methods as part of the Admin template and setup
earlier and will be using themt (sorry don’t have it to refer at my
fingertips right now either) for cleaning-up 2nd level navigation
within a couple of admin applets.
Ramble ramble.
Thanks, I’ll see what I find out about .js file loading in the .