Welcome to another insightful installment of "TWIL," your weekly dose of micro-learning across various tech spheres! This week, our adept contributors invite you to explore the multifaceted world of web development and programming. Let's unwind the complexities of Rails HTML Preprocessors with Katie, who clarifies the essential ERB tags for dynamic content in Rails apps, or iterate through the steps of Creating a Basic Rails Generator, demystifying the customization of the Rails scaffolding process. Meanwhile, Marisa introduces the subtleties of state and effect synchronization in React with useEffect, while Frank reveals the synergy of Heroku, Django, and Webpack in deploying static assets seamlessly. And not to be outdone, Adam shares a swift productivity tip for simultaneous executions across iTerm with Send a Command to All iTerm Panes. Join us this week and enhance your development skills!
Rails HTML preprocessors
In ERB (Embedded Ruby) used in Rails, <% %>
is for executing Ruby code without printing the result, while <%= %>
executes and prints the result into the HTML. This distinction is crucial for managing the dynamic content display in Rails applications
<% %>
will execute the ruby code within the brackets.
<%= %>
puts something into erb file.
<%== %>
is the same as <%= raw %>
which puts something, without escaping it first, into an erb file. (Ruby on Rails Guides.)
<% -%>
will not line break after the expression.
<%# %>
will comment out code within brackets; and is not sent client side (unlike HTML comments, e.g. <!-- this comment will be sent client side -->
).
Visit Ruby Doc for more infos about ERB.
- Rails
- Ruby
Creating a basic Rails generator
While Rails provides many built-in generators to assist in building an application, you can also create your own custom generators to use with the rails generate
command.
Create your generator class, e.g. lib/generators/nothing_generator.rb
:
class NothingGenerator < Rails::Generators::Base
end
Note: If our generator inherits from Rails::Generators::NamedBase
instead of Rails::Generators::Base
, it will require at least one argument in the command line (rails g nothing name
instead of rails g nothing
), which will be magically available to our generator in the name
variable.
Creating the file in lib/generators/
and having the class inherit from Rails::Generators::Base
(or one of its subclasses) is all that Rails needs to make the rails generate nothing
command available (even if it does nothing yet)!
A generator is capable of generating new files, either from simple string inputs or from complex templates that allow for things like variable interpolation.
To create a file from a string input, use the create_file
Thor action:
class ThingGenerator < Rails::Generators::Base
def create_thing_file
create_file 'app/thing.rb', '# This creates a file containing this line <-'
end
end
To create a file from a template, use the template
Thor action:
class ThingGenerator < Rails::Generators::NamedBase
source_root File.expand_path('templates', __dir__)
def copy_thing_file
template 'thing.tt', 'app/thing_named_#{name}.rb'
end
end
In this example, we are inheriting from Rails::Generators::NamedBase
to get a name
when the generate command is run; we will then use that name
to set the name of the file we are creating.
The source_root
tells the generator where to look for template files. In our case, if our generator is in lib/generators/thing_generator.rb
, we should put our template in lib/generators/templates/thing.tt
for the generator to find it. Also note that our template file's extension is .tt
(Thor template).
We can also use the name
variable (as well as any other variables/methods from our generator) within our template file itself. For example:
# lib/generators/thing_generator.rb
class ThingGenerator < Rails::Generators::NamedBase
source_root File.expand_path('templates', __dir__)
def copy_thing_file
template 'thing.tt', 'app/#{name}.rb'
end
private
def name_as_class_name
name.classify
end
end
# lib/generators/templates/thing.tt
class <%= name_as_class_name %>
# This is a thing created with the name <%= name %>
end
Thor templates use a ERB-like syntax for interpolation, so the output of rails g thing cats_and_dogs
here will be:
# app/cats_and_dogs.rb
class CatsAndDogs
# This is a thing created with the name cats_and_dogs
end
- Rails
- Ruby
useEffect and Animations
const logoOpacity = new Animated.Value(0)
const logoOpacityListener = result => {
const { value } = result
if (value === 1) {
props.navigation.navigate("OnboardingIdentity")
logoOpacity.removeAllListeners()
}
}
useEffect(() => {
logoOpacity.addListener(logoOpacityListener)
Animated.timing(
// Animate value over time
logoOpacity, // The value to drive
{
toValue: 1, // Animate to final value of 1
duration: 1000,
},
).start()
}, [])
...
return (
<Animated.View
style={{
opacity: logoOpacity,
}}
>
<Icon
icon="logoWord"
style={{
height: 27,
marginTop: 15,
resizeMode: "contain",
width: 183,
}}
/>
</Animated.View>
)
For a deeper dive, visit Marisa's blog post: Animating with useEffect in React.
- React
Heroku, Django, Webpack and Collectstatic
Heroku runs collectstatic
for you when you've properly configured static files in your Django application. This is cool, because before you'd have to get crafty with getting this command to run after your application completes the build. There was even once a Heroku buildpack that you added to a project just to run collectstatic
after the main Python buildpack had completed.
Unfortunately, this isn't as helpful if you're using node and likely webpack to compile assets as part of the same build pipeline. What will happen is that Heroku will detect your Python app first, build it, run collectstatic
, and then move on to your node buildpack. This means that collectstatic
runs before your assets have been compiled and Django throws a 500 cause it can't find the stylesheet and main JS entrypoint.
But it's okay, we can handle this. Heroku will default to looking for a build
command in your npm scripts but they also give us a unique command that it will use exclusively to build your node app; heroku-postbuild
.
So the solution? Add && python
manage.py
collectstatic
to the end of your npm build!
If your build command looks like: webpack -p --config webpack.prod.config.js
. Then create a heroku-postbuild
that looks like:
webpack -p --config webpack.prod.config.js
&& python manage.py collectstatic --noinput
Now collectstatic
will run after you've compiled assets, and it will move them to the correct static file directory and add them to the manifest! Problem solved.
(I recommend using heroku-postbuild
as a way to separate concerns. This will only run on Heroku, and you don't want to mess with existing CI that's already using your build
command as is.)
To further optimize this, you can disable the automated collectstatic
by adding the env variable DISABLE_COLLECTSTATIC = 1
to your project's config vars.
This way it will only run once... when you've told it to :)
Resources
- Django
- Heroku
- Webpack
Send a command to all iTerm panes
You can run a command in all of your iTerm panes at the same time with:
⌘Command + ⇧Shift + I
- Iterm
Get Flakey Tests to Fail
When trying to fix a flakey test in rails you can run:
while bundle exec rspec spec; do :; done
This will run you test or test suite until RSpec fails and returns a non-zero exit code.
- Rails
- rspec