Why are Rails assets not isolated between models? - ruby-on-rails

I have these a coffeescript file for a model entree that just instanciates a class in another coffeescript file:
jQuery(document).ready ->
ch = new CepageHandling
ch.handleKeyPress()
The handlePress function captures keyup events on a control.
I have another model vin where I want to enable the same feature. I'm surprised to see I don't need to do anything (it already has the same html), it's already working, even though the coffeescript for the vin model is completely empty. I assume that the created javascript for entree gets called even when I'm not on this page.
I have seen the same behavior with scss files, where style defined for one model gets applied to others if the descriptors match. Can someone explain (or point to some article) if this is normal behavior that assets are not isolated in rails? I really have a hard time grasping how it works.

The default manifest files (application.js, etc) do require_tree . which will load all files on all pages, concat them all together in production, etc. If you want things to be isolated you'll need to put a test in your ready handler to skip this code in some cases, or you'll need more manifests (and not use application.js for example) to silo your code per page. I suggest you read every word of the asset pipeline Rails Guide very carefully... required reading!

It happens because of the manifest file application.js, more precisely in this line of code:
//= require_tree .
What this means is that all .js files contained inside the /assets/javascripts/ folder would be loaded to your views.
As your entree.js is already loaded and using the JQuery document ready function, it searches for the rules of your file inside all of your views.
This means that all of your pages that contains this ch element will get the same behavior.

Related

A way to display a list of public assets

(Been looking for this for ages over internet...).
Been working with very old npm packages recently and seems that they cannot be loaded properly within Rails-6 (I know I could create a question by each cases, but I'd like to learn to handle this myself since every time it is for a different reason).
I'd like (as for debugs and in development mode only) to display the list of available all assets, including js, css, images, and anything else available at public level (the client could load). So it should be a set of compiled assets ?
Similarly to http://localhost:3000/rails/mailers like http://localhost:3000/rails/assets ?
Displaying the list of all available assets (prior compilation, also for debug intents) could also be great.
This might do what you want:
Rails.application.assets.each_file do | pathname |
# ...
end
This will enumerate every file of which Sprockets is aware. You can run that at rails c or build a simple controller to dump the list into a view if you prefer. For more information, see https://stackoverflow.com/a/11005361.
If you're not using Sprockets (e.g. a newer Webpacker-based application) then, obviously, you'll need a different solution.
You can run rails assets:reveal and see all the available assets:
$ rails assets:reveal
application.js
application.js.map
application.css
application.scss
...
To view the full path, use rails assets:reveal:full:
$ rails assets:reveal:full
/home/{REDACTED}/app/assets/builds/application.js
/home/{REDACTED}/app/assets/builds/application.js.map
/home/{REDACTED}/app/assets/builds/application.css
/home/{REDACTED}/app/assets/stylesheets/application.scss
...

Organize GraphQL files in directories in Rails

Upon running rails g graphql:install, a set of useful base type files are created in /app/graphql/types for us to extend when defining our own types. When running any of the generators, it creates these files in the same folder also. I set about creating sub directories thinking I could add some sense to this giant catch-all directory, but couldn't get things to load properly.
Since there is a base file for each type (base_enum.rb, base_object.rb, etc.), I created a folder for extensions of each of these types (enum_types, object_types, etc.). This broke auto loading though and I had to explicitly import these files to be able to use these custom types. So, at the top of query_type.rb, mutation_type.rb and app/graphql/mutations/base_mutation.rb I added the following:
['enum_typs', 'input_object_types', 'interface_types', 'object_types', 'scalar_types', 'union_types'].each do |dir|
Dir[File.dirname(__FILE__) + "/#{dir}/*.rb"].each {|file| require file }
end
This allowed things to run, but any change would break auto loading so I would have to restart the server on each change. I started reading through this article about auto loading on the rails site, but it was quite honestly a little over my head. Though it led me to believe I had to either find the correct names for my folders or namespace the objects defined in my type definition files properly to be able to do this.
Is there a sane way to organize these files in sub-directories which doesn't break auto loading? Do most projects just have a flat folder structure for these files?
Thank you!

Rails 4 assets - two different digests getting generated

I clearly must be Doing Something Wrong here. I'm wrestling with the asset pipeline (again). I have a custom font, and it seems to me to get everything to compile properly I need to use asset_path() in multiple places, but it's having an unexpected effect.
I realize there are several ways to do this, but here's what I have currently:
In application.css.scss.erb:
#import "<%= asset_path("my-font.css") %>";
my-font.css's source file is app/assets/stylesheets/my-font.css.erb (it needs to be an .erb because I am also using asset_path() there as well).
In application.rb I am adding my-font.css to the precompile list.
config.assets.precompile << 'my-font.css'
When I clean out public/assets and run rake assets:precompile Everything's getting compiled, with digests, but the digest applied to the actual file is not the same as the digest calculated and put in to application.css.
The resulting file is
public/assets/my-font-2f25682a1ea904a866ef9f44101a5a2e.css but in public/assets/application-bba2edaee36771f4bdb5c89b8ec90aaf.css the reference to it is:
#import url(/assets/my-font-ed843d3b174ca427edf963e473ad9e9b.css);
I realize I'm probably using asset_path() more than I should, and also importing files via url() instead of requiring them, but this has gotten me the closest to having things working.
I suspect one of the digests is being calculated on my-font.css before it goes through ERB, and the other after, but I don't understand why nor how to fix it.
Suggestions?
I would guess that you're cleaning your assets just by emptying public/assets. That's not enough, you'll also need to empty your tmp/cache/assets, or just run rake assets:clobber to do both.
I've resolve this kind of dependency by injecting the raw contents of the asset you want to bundle into a composite asset like application.scss.erb. You need to explicitly declare the dependency (so that changes in my-fonts.css cause a regenerations of application.css) and then inject the contents:
application.scss.erb:
// Should be at Top of File
//= depend_on_asset my-fonts.css
//... wherever in the file you want the contents injected:
<%= environment['my-fonts.css'] %>
How does this work? During asset pipeline compilation, the environment here has a hash of all pre-compiled asset contents. This allows you to inject the compiled contents from my-fonts.css into your composite asset. Because we're manually injecting the value, we need to explicitly create a dependency to track this relationship via depend_on_asset.
One thing to keep in mind is that multiple asset pre-processors (SCSS, ERB, etc) are processed from the "outside in", so the contents of the my-fonts.css asset will be compiled/injected during the ERB processing as CSS output. They will be included within the asset before SCSS processing. This shouldn't pose a problem, because if this is an SCSS asset, any SCSS references will be compiled before injection into the parent asset.

Rails 3.2 + CoffeeScript + Namespacing + Separate Files = Confusion

I have one companion script file for a Rails model, that uses code I've broken down into a hierarchy of over a dozen classes, for things like jQuery/Bootstrap UI code, factoring out similarities between different types of dialog, and so on. Let's say I'm working with articles.js.coffee as the "main page script" here.
I can define Coffeescript classes, namespace them as something like window.ourproject.OurUIDialog, and save them in separate, per-class source files such as app/assets/javascripts/OurUIDialog.js.coffee. Restart the Rails server, and that class can be subclassed, e.g., window.ourproject.PostInfoDialog extends window.ourproject.OurUIDialog. As long as PostInfoDialog is in articles.js.coffee (where the instantiation of the PostInfoDialog is), all is well.
But, if I move the subclass (PostInfoDialog) out into a separate file, e.g., PostInfoDialog.js.coffee, then attempting to do anything at all with it within the main articles script produces
Uncaught TypeError: Cannot read property 'prototype' of undefined
Again:
This revolves around a Rails model's companion script file, here called articles.js.coffee;
window.ourproject.OurUIDialog gets picked up whether it's in its own file or in articles.js.coffee
window.ourproject.PostInfoDialog (which extends OurUIDialog) can only be used if it's not in a separate file, even though viewing the generated HTML shows PostInfoDialog being included with all the other script files.
I'm tearing my hair out trying to figure this out, and I didn't have much left to begin with. Any ideas?
Pretty sure that Trevor Burnham answered my question when he answered this one; I just didn't see it the first dozen times I searched. :-P
Thanks to both of you for reading this one, though. :-)

How can I dynamically include modules in nested directories?

I want to dynamically load code by traversing a directory structure and dynamically load whatever modules I find there.
The purpose for doing so is to run a series of validations. If a top-level validation fails, any child validations will not be run.
My thinking was that a controller object could scan the directories, build up a hierarchy of modules and then make the decisions on whether or not to traverse a particular part of the tree based on the success/failure of higher-level validations.
For example, I might have a series of validations I want to run against a regex, however, none of the validations should be run if the regex doesn't exist or is empty. In this case, the top level directory would contain just the exists validation, and a child directory would contain all the other validations to be run if the regex exists.
Being able to define these validations in separate files and create the needed hierarchy would be extremely useful for ease of adding additional validations later, rather than having to crack open an existing class and add methods.
Is there a way an application can dynamically scan a directory, save the filenames in a collection and then use the elements of that collection in a require? I don't think so. What about a load?
Is there any way to achieve such a design? Or am I thinking about it all wrong and should think of some other methodology instead?
Your request is very doable, but no language will do it for you automatically. You have to write the code to dive into the directories, determine the existence of the tests and then decide whether you should drill down further.
Ruby will help you though. There is the Find module, which is included in the standard library. This is from its docs:
The Find module supports the top-down traversal of a set of file paths.
For example, to total the size of all files under your home directory,
ignoring anything in a "dot" directory (e.g. $HOME/.ssh):
require 'find'
total_size = 0
Find.find(ENV["HOME"]) do |path|
if FileTest.directory?(path)
if File.basename(path)[0] == ?.
Find.prune # Don't look any further into this directory.
else
next
end
else
total_size += FileTest.size(path)
end
end
From that code you would look for the signatures of the files and embedded folders, to decide if you should drill down further. For each file found that is one you want, use require to load it.
You can find other examples out on the "internets" showing how people use Find. Also the Dir module has similar functionality using glob, only you have to tell it where to descend, and then can iterate over the returned results.

Resources