Ruby on Rails - Using helpers inside css erb file gives undefined method - css

I have a css.erb file which contains the styling of one of my pages. I have a helper which preformats a URL of a given image based on the location of that image.
When I call the helper function from the view, the output is expected (a string containing the URL for of the image). However, calling it in the css.erb file gives me an undefined method error even though I copy and paste the same function into my css file.
It's as if the helper is not included in the css file and is ignored.

Helpers are not available by default to templated .css files. They are intended to help in view construction only. However, you can try the workaround mentioned here using an initializer:
Rails.application.assets.context_class.instance_eval do
include YourHelperModule
end
Alternatively, if you only need this for one or a few files, you can use the solution mentioned here, by adding this code to the top of the .css.erb file:
<% environment.context_class.instance_eval { include YourHelperModule } %>

Related

How to import styles from css files into an .ejs template and send it over email?

What i want to do:
Send one email with styles;
Have separate files, one for my .ejs template and one .css for styles that correspond to that template.
What the problem is:
If i create separate routes for the styles and insert it into the HTML, the user will need to "authorize" the download of these styles;
If i just import like normal HTML, it will not go through the email.
What am i using:
Express.js
Typescript
EJS
nodemailer
What is my file structure like at the moment:
src
views
index.ejs
style.css
internal_view_group
style.css
internal_template_name
style.css
locale
pt-br.ejs
en-us.ejs
public_view_group
style.css
public_template_name
style.css
locale
pt-br.ejs
en-us.ejs
Ok, if the directory is a little messy or hard to understand, let me break it down for you:
Folder "views" contains all my templates and styles, it also contains my index.ejs, that's what i'll call for when rendering the HTML, this index will then call styles from the group, template and then call the HTML from template, considering the language it uses. It also has a style.css, a global stylesheet that must be used in all templates, regardless of it's group.
Folder "internal_view_group" is a group of templates, for example, we have an internal group, templates used for internal communication, and a public group, used for the general public communication. It also has a default style.css, that is applied to every template inside this group.
Folder "internal_template_name" is a template, it has it's locales inside "locales" folder and a stylesheet that must be applied onto the called locale.
How can i have this level of organization on my code, having separate files and still work, considering the section "The problem is"?
Since you use your index.ejs to call all other templates and styles, you can also directly inject the styles into this index.ejs using the <%- %> tag from EJS.
What this tag does: import a file (usually an .EJS), read it's content and output it unscaped to the HTML.
so what you want to do into the index.js is something similar to this:
<head>
<%-
'<style>'
+ include(`./style.css`)
+ include(`./${template_group}/style.css`)
+ include(`./${template_group}/${template_name}/style.css`)
+ '</style>'
%>
</head>
<body>
<%- include(`./${template_group}/${template_name}/locale/${locale}.ejs`) %>
</body>
This will output all style RAW contents into the code (not a minified version).
The reason for the style tag being inside strings is that VSCode may report an error in your code because of EJS tags inside style sections, with this, only the < at the start of <style> will be reported as "wrong", but with nothing at output terminal telling you.
If you find that the final size of HTML code that you want to send is too large and may become a problem, you can use javascript prototype.String functions after the include, like include('./style.css').replaceAll(' ', ''), to replace all spaces but leave line breaks (not tested)

How to load CSS file in qooxdoo dynamically

Is there a special qooxdoo class to load CSS files dynamically like qx.util.DynamicScriptLoader does for JavaScript files?
For example, depends on user choice what geo maps he wants to use an application loads specific JavaScript and CSS files. I can get .js file via qx.util.DynamicScriptLoader class but for css I use externalResources section in Manifest.json file which always loads a style file (am I right?).
A dynamic possibility to include css files, e.g. in the constructor of a class, is using qx.bom.Stylesheet.includeFile like this:
qx.bom.Stylesheet.includeFile("https://myserver.com/my.css");
This way I've successfully built completely dynamic wrappers for packages/frameworks where all external resources are loaded only on wrapper class instantiation in conjunction with qx.util.DynamicScriptLoader.
If the css files are within your projects resources, you have to call qx.util.ResourceManager.getInstance().toUri() on the resource name and feed it then into qx.bom.Stylesheet.includeFile.
Lets say you have a css file in your project in resource/myframework/my.css you have to first create an #asset hint like this in your wrapper class:
/*
* #asset(myframework/my.css)
*/
and afterwards, e.g. in the constructor you call:
qx.bom.Stylesheet.includeFile(qx.util.ResourceManager.getInstance().toUri(
"resource/myframework/my.css"
));
In order to avoid multiple loading of the css file, I've added a static class member CSS_INCLUDED to the wrapper class, initialized to false and then set to true after calling qx.bom.Stylesheet.includeFile which results in the this code:
if(my.wrapper.CSS_INCLUDED === false) {
qx.bom.Stylesheet.includeFile(qx.util.ResourceManager.getInstance().toUri(
"resource/myframework/my.css"
));
my.wrapper.CSS_INCLUDED = true;
}
This way subsequent instantiations do not load the css file again.

Dotless MVC bundling issue when importing same less file twice

Im trying to accomplish following structure using dotless:
styles/variables.less - contains, well, all variables like below
#color:green;
styles/component1.less - some random component specific style which imports variables.less
#import "variables";
body {
background:#color;
}
styles/component2.less - some more styles which also imports the global variables.less file
#import "variables";
a {
color:#color;
}
BundleConfig.cs - declaring the bundle like below. Im using this bundling addition: https://gist.github.com/benfoster/3924025
bundles.Add(new Bundle("~/styles/css", new LessTransform()).Include("~/styles/component1.less", "~/styles/component2.less"));
Everything works fine when Debug is set to true
But When Debug is set to false
Only the first file passed in Include method of bundle resolves #import "variables". The rest just fail.
Below is the output of declaring "~/styles/component1.less" first
bundles.Add(new Bundle("~/styles/css", new LessTransform()).Include("~/styles/component1.less", "~/styles/component2.less"));
Output when "~/styles/component2.less" is declared first
bundles.Add(new Bundle("~/styles/css", new LessTransform()).Include("~/styles/component2.less", "~/styles/component1.less"));
Strangely - it works if i import different files in component1 and component2
For instance, if i rename "varibales" to "variables.less" in either file just to make those imports look a bit different. It works. Like below
styles/component1.less
#import "variables.less"; // added extension here
body {
background:#color;
}
Any thoughts? Ive been fidling with this for days..
Edit
Reasons for using this structure:
To send seperate less files in debug mode, as it makes its easier to debug. Line number comments aren't very helpful
To concatenate and minify all the less files when served in production.
Adding #import "variables" on top of every file is ugly.
So, tried declaring variables.less as part of .Include("variables.less", file-dependant-on-variables.less, ...)
Which apparently doesnt work because of some scoping issues mentioned here: Dotless - Can't reference less variable in separate file with MVC Bundling
There is a fix for that, concatenating contents of every single less file and use Less to parse that concatinated file instead. Example here, https://groups.google.com/forum/?fromgroups#!topic/dotless/j-8OP1dNjUY
But in that case, i dont seem to be able to get minified version of the parsed file.
According to the docos:
In v1.3.0 - v1.3.3 #import imports a file multiple times and you can
override this behaviour with #import-once.
In v1.4.0 #import-once has been removed and #import imports once by
default. This means that with the following
The second import of variables is ignored and the variable #color:green; is only defined in the scope of the first component; being undefined in the scope of the second component it would probably end up with the rule or even the entire less file ignored (I'm not that intimately familiar with the default behavior, you could just add in extra properties and rules and see what happens). You could confirm this by inspecting preprocessor logs or otherwise allowing its errors to be traced in the console.
Importing variables at a "higher" level into shared scope like #Hans suggested (+1) should fix this. A tentative alternative could be to downgrade the preprocessor to v1.3.0-v1.3.3 so that #import fires multiple times. Since my preference when dealing with css pre-processors revolves almost exclusively around their variable and mixin functionality I myself could possibly see this as an acceptable option.
I might be missing something here since you didn't state why you are trying to achieve this structure, but you could easily avoid the problem AND generate a smaller resulting bundle by rearranging your file structure. Create a 4th less file with the following content:
#import "variables.less";
#import "component1.less";
#import "component2.less";
And just throw this file into the bundler. The bundle will end up smaller because variables.less is included only once instead of twice, and this definetly works with Dotless.
#o.v. is absolutely right. Dotless generates the next error during parsing the second *.less file in the bundle:
variable #color is undefined on line 4 in file
'..\styles\component2.less':
[3]: a { [4]: color:#color;
----------^
If you look at dotless sources you will find CheckIgnoreImport method in dotless.Core.Importers.Importer class which is called for each imported file:
/// <summary>
/// returns true if the import should be ignored because it is a duplicate and import-once was used
/// </summary>
/// <param name="import"></param>
/// <returns></returns>
protected bool CheckIgnoreImport(Import import, string path)
{
if (_rawImports.Contains(path, StringComparer.InvariantCultureIgnoreCase))
{
return import.IsOnce;
}
_rawImports.Add(path);
return false;
}
Currently import.IsOnce value is always true (see dotless.Core.Parser.Parsers class, line 1080). And you don't have opportunity to change this behavior outside the dotless library.

Jade - calling page specific css pages

I have page specific css files I would like to call automatically. Does anyone have a nice way of doing this elegantly?
This should do it
link(rel="stylesheet", href="#{req.path + '.css'}", type="text/css")
Where you pass either req (the request object) as a local variable when rendering the jade template (or even just pass in req.path as path). This could just be handled in your layout.jade and it will work for each of your route paths.
If you want to get fancy, you could establish a consistent pattern where a page's route maps 1 to 1 to a filesystem path for a .css file in your public directory. In that case you could easily but the stylesheet link tag inside a conditional and only link to the .css file if you find a matching one on disk.

Using directives in new files

Is it possible to have additional "using" directives automatically added to my new aspx.cs files so that I do not have to keep typing the same ones over and over again (i.e. custom namespace using directives)
You can edit the files that are used by the template. Better yet, create your own. File + Export Template.
You don't have to type them in. When writing the code, type in the name of the class (without the namespace). Then hit CTRL+.. That will open up the resolve type intellisense helper. It will add the using statement to the top of the file. No scrolling necessary.

Resources