Dynamic Assets - can it be done?

I’m looking for 3 areas to work as dynamic assets:

image_path, javascript_path, and stylesheet_path

When I say dynamic, I mean that they will be dynamic through
controller/models. I have been working through approx. 12 hours of
searches to satisfy my answer to this question but am not finding much
luck.

The closest things I’ve found enabling this are use of config for assets
(which is normally done for CDNs), or monkey-patching the tag helpers,
which still won’t give me what I want.

The reason why I want to do this is to provide for themes. As an
example, if your rails app contained 20 different themes, a theme would
be composed of layouts, images, javascripts, stylesheets, etc. You
wouldn’t want to have to change your theme through an initializer and
stop/restart your app for it to work. I’ve already done a lot of leg
work with getting my themes into the MVC structure.

I just need the ability to change the three paths above using either a
custom call to a module, or through the application controller.

Can it be done and if so, how?

Many thanks.

Alpha B. wrote:

I’m looking for 3 areas to work as dynamic assets:

image_path, javascript_path, and stylesheet_path

When I say dynamic, I mean that they will be dynamic through
controller/models.

That only barely helps clarify. Defining something by repetition
doesn’t work. :slight_smile:

I have been working through approx. 12 hours of
searches to satisfy my answer to this question but am not finding much
luck.

The closest things I’ve found enabling this are use of config for assets
(which is normally done for CDNs), or monkey-patching the tag helpers,
which still won’t give me what I want.

No, it probably won’t unless you monkey-patch to look up the current
user’s
theme each time – which is doable but potentially costly.

The reason why I want to do this is to provide for themes. As an
example, if your rails app contained 20 different themes, a theme would
be composed of layouts, images, javascripts, stylesheets, etc. You
wouldn’t want to have to change your theme through an initializer and
stop/restart your app for it to work. I’ve already done a lot of leg
work with getting my themes into the MVC structure.

Is there a reason that you didn’t use something like Liquid, which seems
to have been designed for exactly this purpose?

I just need the ability to change the three paths above using either a
custom call to a module, or through the application controller.

Can it be done and if so, how?

Of course it can be done by monkeypatching as described above. Whether
it should be done that way is another question. :slight_smile:

Another possibility: I recently found out that Haml can use Sass as a
markup filter. This has some interesting potential for dynamically
generated CSS.

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Many thanks.

On Thu, Jan 14, 2010 at 7:51 PM, Alpha B. [email protected]
wrote:

I’m looking for 3 areas to work as dynamic assets:

image_path, javascript_path, and stylesheet_path

I just need the ability to change the three paths above using either a
custom call to a module, or through the application controller.

Can it be done and if so, how?

Sounds like a fun and interesting project. I would be interested in
finding out your
final solution.

You might consider adding to the config object used in intitializer ala
the
way
action mailer and actioncontroller use it for UrlWriter. and then having
a
mixin that
renames the above methods and prepends a different directory for the
images,
javascript
and style sheets. making some common theme convention that will be
assumed
under
the themes directory will make the relative addressing of the image path
etc
more sane.

thats one thought. good luck. good tests will make a difference as you
try
multiple solutions
and will pay for themselves.

Curtis S. wrote:

On Thu, Jan 14, 2010 at 7:51 PM, Alpha B. [email protected]
wrote:

I’m looking for 3 areas to work as dynamic assets:

image_path, javascript_path, and stylesheet_path

I just need the ability to change the three paths above using either a
custom call to a module, or through the application controller.

Can it be done and if so, how?

Sounds like a fun and interesting project. I would be interested in
finding out your
final solution.

You might consider adding to the config object used in intitializer ala
the
way
action mailer and actioncontroller use it for UrlWriter.
[…]

That probably won’t work. The OP needs different paths for each user,
while the config object is site-wide. (Unless there’s a way to put a
method in there and evaluate it as necessary.)

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Thanks guys - I appreciate both of your responses.

Marnen, I did look at liquid previously and did so again this morning.
However, while I like what the developers are trying to do with certain
features, it’s not for me.

And, the nice thing about my system is that there will always be a
default theme in place in a set location, for instance:

public/themes/default

That will be the base default theme.

What I have to really consider are quite a few things. First and
foremost are asset tags. If the asset tags don’t include the current
theme, then caching is not going to work properly. There is an
interesting bit in the helper though:

ASSETS_DIR = defined?(Rails.public_path) ? Rails.public_path : “public”
JAVASCRIPTS_DIR = “#{ASSETS_DIR}/javascripts”
STYLESHEETS_DIR = “#{ASSETS_DIR}/stylesheets”
JAVASCRIPT_DEFAULT_SOURCES = [‘prototype’, ‘effects’, ‘dragdrop’,
‘controls’].freeze unless const_defined?(:JAVASCRIPT_DEFAULT_SOURCES)

So, my first decision is how to dynamically modify the assets_dir. I
know that assets can be modified through URLs (CDNs), but again, I’m
just now touching into looking through quite a bit of code to make sure
I understand what is going on step by step. Then, I’ll create some test
code to play with.

Alpha B. wrote:

Thanks guys - I appreciate both of your responses.

Marnen, I did look at liquid previously and did so again this morning.
However, while I like what the developers are trying to do with certain
features, it’s not for me.

[…]

Why not? I’ve never used it, but it is a widely used solution to the
exact problem you’re trying to solve.

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Marnen Laibow-Koser wrote:

Alpha B. wrote:

Thanks guys - I appreciate both of your responses.

Marnen, I did look at liquid previously and did so again this morning.
However, while I like what the developers are trying to do with certain
features, it’s not for me.

[…]

Why not? I’ve never used it, but it is a widely used solution to the
exact problem you’re trying to solve.

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

A few reasons. First, I don’t like the markup style they are using when
interacting with templates. They also go far above and beyond limiting
what I’m eventually going to do and that is implementing hooks within
templates. In addition, I really do not try to use other people’s
plugins (unless it’s something very minor). This is mainly because of
how I program, personally. I like to be able to adjust/alter and
understand exactly what is being developed and make alterations as need
be. Going with a plugin on this scale hampers my development as their
ideas and mine might differ and I’d end up monkey patching a plugin.
That’s not for me.

I want to develop my own work. I can certainly learn from others and
their work, but that’s something entirely different.

On Jan 15, 3:02Â pm, Alpha B. [email protected] wrote:

Thanks guys - I appreciate both of your responses.

Marnen, I did look at liquid previously and did so again this morning.
However, while I like what the developers are trying to do with certain
features, it’s not for me.

As Marnen said you may want to reconsider - mephisto for example uses
liquid for themes and so on and you can change those on the fly

So, my first decision is how to dynamically modify the assets_dir. Â I
know that assets can be modified through URLs (CDNs), but again, I’m
just now touching into looking through quite a bit of code to make sure
I understand what is going on step by step. Â Then, I’ll create some test
code to play with.

I wonder whether you’re overthinking things slightly. If you had a
helper called current_theme_path that returned the path to the current
theme (eg themes/default/ initially, themes/minimalist/ etc…

then you should be able to stuff like style_sheet_tag
(current_theme_path + ‘blah.css’) or image_tag(current_theme_path +
‘heading.png’)

Fred

Fred

I wonder whether you’re overthinking things slightly. If you had a
helper called current_theme_path that returned the path to the current
theme (eg themes/default/ initially, themes/minimalist/ etc…

then you should be able to stuff like style_sheet_tag
(current_theme_path + ‘blah.css’) or image_tag(current_theme_path +
‘heading.png’)

I think this is very pragmatic.

Frederick C. wrote:

On Jan 15, 3:02Â pm, Alpha B. [email protected] wrote:

Thanks guys - I appreciate both of your responses.

Marnen, I did look at liquid previously and did so again this morning.
However, while I like what the developers are trying to do with certain
features, it’s not for me.

As Marnen said you may want to reconsider - mephisto for example uses
liquid for themes and so on and you can change those on the fly

So, my first decision is how to dynamically modify the assets_dir. Â I
know that assets can be modified through URLs (CDNs), but again, I’m
just now touching into looking through quite a bit of code to make sure
I understand what is going on step by step. Â Then, I’ll create some test
code to play with.

I wonder whether you’re overthinking things slightly. If you had a
helper called current_theme_path that returned the path to the current
theme (eg themes/default/ initially, themes/minimalist/ etc…

then you should be able to stuff like style_sheet_tag
(current_theme_path + ‘blah.css’) or image_tag(current_theme_path +
‘heading.png’)

Fred

Thanks Fred, that’s good info. When I start to get involved into deeper
areas of rails, I do tend to overthink things initially. As I become
more familiar with the environment, I scale my thoughts back
considerably.

I’m going to test out a few of your ideas and see how it works out.

Fred, so the issue with the code above is this:

When using such a helper it will display:

link href="/stylesheets/public/themes/default/stylesheets/default.css"
media=“screen” rel=“stylesheet” type=“text/css”

… which won’t work.

The issue here is that /stylesheets is being used as the default
stylesheets_path through rails. In order to utilize such a helper, I
have to first change the stylesheet_path to go to ‘’.

The same would have to be done for image_path, javascripts_path, etc.

Curtis S. wrote:

That seems simple enough - you may be able to monkey patch those
methods
in the controller level to do ‘./themes/current_user.theme/’

What bothers me is that you can’t simply decide a default path to your
assets through a config.

I should be able to set:

config.asset_tag_helper.image_path = ‘’
config.asset_tag_helper.javascripts_path = ‘’
config.asset_tag_helper.stylesheets_path = ‘’

However, looking through all of the code I just don’t see a way to tie
into changing those default paths unless I monkey patch. I was hoping
there would be another way which is why I opened the topic.

On Fri, Jan 15, 2010 at 7:50 AM, Alpha B. [email protected]
wrote:

stylesheets_path through rails. In order to utilize such a helper, I
have to first change the stylesheet_path to go to ‘’.

The same would have to be done for image_path, javascripts_path, etc.

That seems simple enough - you may be able to monkey patch those
methods
in the controller level to do ‘./themes/current_user.theme/’

I am able to get it to work by doing the following:

Monkey Patching :: asset_tag_helper.rb

def javascript_path(source)
compute_public_path(source, ‘themes’, ‘js’)
end

def stylesheet_path(source)
compute_public_path(source, ‘themes’, ‘css’)
end

def image_path(source)
compute_public_path(source, ‘themes’)
end

And adding a helper: (this will of course change)

def current_theme_path(type)
path = @opt_default_theme + “/images/” if type == ‘img’
path = @opt_default_theme + “/stylesheets/” if type == ‘css’
path = @opt_default_theme + “/javascripts/” if type == ‘js’
path = @opt_default_theme + “/swfs/” if type == ‘swf’
return path
end

And finally in my layout:

<%= stylesheet_link_tag(current_theme_path(‘css’) + @opt_theme + ‘.css’)
%>
<%= javascript_include_tag(current_theme_path(‘js’) + @opt_theme +
‘.js’) %>

Which makes all stylesheets and javascripts dynamically loaded based on
options set in the site on the fly.

However, it still doesn’t solve the problem of assets…

Frederick C. wrote:

On Jan 15, 3:50Â pm, Alpha B. [email protected] wrote:

Fred, so the issue with the code above is this:

When using such a helper it will display:

link href=“/stylesheets/public/themes/default/stylesheets/default.css”
media=“screen” rel=“stylesheet” type=“text/css”

That sounds like the path you passed didn’t have a leading / (and you
don’t want the public in there).

Fred

Fred, as always, you were correct. I removed the monkey patching code
and then I fixed the test helper to:

def current_theme_path(type)
path = “/themes/” + @opt_default_theme + “/images/” if type == ‘img’
path = “/themes/” + @opt_default_theme + “/stylesheets/” if type ==
‘css’
path = “/themes/” + @opt_default_theme + “/javascripts/” if type ==
‘js’
path = “/themes/” + @opt_default_theme + “/swfs/” if type == ‘swf’
return path
end

And finally in my layout:

<%= stylesheet_link_tag(current_theme_path(‘css’)+ @opt_theme +‘.css’)
%>
<%= javascript_include_tag(current_theme_path(‘js’)+ @opt_theme +‘.js’)
%>

… and it works.

I’ll work with this bit of code instead and see how it affects asset
caching.

On Jan 15, 3:50Â pm, Alpha B. [email protected] wrote:

Fred, so the issue with the code above is this:

When using such a helper it will display:

link href=“/stylesheets/public/themes/default/stylesheets/default.css”
media=“screen” rel=“stylesheet” type=“text/css”

That sounds like the path you passed didn’t have a leading / (and you
don’t want the public in there).

Fred

On Jan 15, 2010, at 9:31 AM, Alpha B. wrote:

That sounds like the path you passed didn’t have a leading / (and you
‘css’
<%= stylesheet_link_tag(current_theme_path(‘css’)+ @opt_theme +’.css’)
%>
<%= javascript_include_tag(current_theme_path(‘js’)+ @opt_theme +’.js’)
%>

… and it works.

I’ll work with this bit of code instead and see how it affects asset
caching.

I don’t understand why you can’t use a stylesheet like:

application.css

that handles the general case or “default theme”, as you refer to it,
and then simply serve up a second stylesheet after that based on
preference, as:

<%= stylesheet_link_tag :application %>
<%= stylesheet_link_tag @user_theme_stylesheet if @user_theme_stylesheet
%>

You can then simply implement a before filter in your controller that
sets @user_theme_stylesheet based on user preference and relies on the
CSS proximity rule disambiguation to decide what CSS rule to apply.

Have I misunderstood your problem?

Steve R. wrote:

I don’t understand why you can’t use a stylesheet like:

application.css

that handles the general case or “default theme”, as you refer to it,
and then simply serve up a second stylesheet after that based on
preference, as:

<%= stylesheet_link_tag :application %>
<%= stylesheet_link_tag @user_theme_stylesheet if @user_theme_stylesheet
%>

You can then simply implement a before filter in your controller that
sets @user_theme_stylesheet based on user preference and relies on the
CSS proximity rule disambiguation to decide what CSS rule to apply.

Have I misunderstood your problem?

Yes, it’s not that simple. My problem isn’t with CSS directly. My
problem lays simply in delivering up the paths to the css files, and the
js files, and the swf files, and the image files, and the layout files -
depending on what theme is set as the default theme for the site.

I no longer have these issues thanks to Fred.

I already have a layouts system implemented where based on any given
theme, a user can decide on exactly what layout to use for every single
page or grouped by controller type. It’s very detailed but it works
great.

The only issues I had that were remaining were handling of images, css,
js, and swfs, relative to the path of the theme and still have the
ability for rails to manage these assets.

I’ve tested out the new code and it works great. The assets and
timestamps are working properly for root path and for the theme path.

So, I’m able to do the following:

==============

When a user goes to administrative options and selects what theme they
want to use, the entire path to all assets changes for each theme (which
includes layouts, images, javascript, stylesheets, and swfs) while none
of MVC templates are affected.

This is what I wanted to do and it’s working now 100%. I’m just
cleaning up the code and making it more practical and dry.

I’ll revisit with some code once I’m finished.

+1 for LIQUID and/or Haml and Sass. Interestingly enough there are
some changes in the Sass 2.4 source code that might be exactly what
you’re looking for:

http://nex-3.com/posts/89-powerful-color-manipulation-with-sass

Obviously it’s edge at this point, but you can use the haml master
branch to check out some of the new features mentioned in the article:

http://github.com/nex3/haml

Chris Eppstein has some nice examples of the Compass Color module
here:

http://chriseppstein.github.com/compass-colors/

Hope this helps a little bit.

cool