Time for the Planet® is a website to help raise money and find entrepreneurs to create companies dedicated to fight climate change.
Purchasing shares is done using a Typeform, whose link is found on this page.
Projets content is controlled by editors via a CMS.
Check the website : https://www.time-planet.com
Time for the Planet® is developped using Ruby on Rails.
For JavaScript, it uses the framework Stimulus.
Editor can publish new contents using Active Admin with the theme Arctic Admin.
A continuous integration system is set up using Circle CI to launch tests from Github. The website is deployed through Heroku. Errors are catched with Sentry.
Sidekiq is used for background processing.
This website uses only the grid system of Bootstrap
For CSS, we use the BEM (Block Element Modifier) methodology. The principle is to organize CSS code by component (the Block), then by Elements of the components, and then create variants (the Modifiers) if needed. We use SCSS, so the different classes should be nested.
Example :
# app/assets/stylesheets/components/_card.scss
.Card {
display: flex;
padding: 1 rem;
border-radius: 3px;
&--dark {
background-color: $black;
color: $white;
}
&--light {
background-color: $white;
color: $black;
}
&-title {
font-weight: bold;
font-size: 1.5;
}
&-content {
font-size: 1rem
&--dark {
color: $grey-50;
}
&--light {
color: $dark-grey;
}
}
}
git clone git@github.com:EmmanuelleN/time-planet.git
cd mon-time-planet
ruby -v
The ouput should start with something like ruby 2.6.5
If not, install the right ruby version using rbenv (it could take a while):
rbenv install 2.6.5
Using Bundler and Yarn:
bundle && yarn
Most of the sensitive data you need like api keys and such are in the credentials contained in an encrypted file.
To get the master key, needed to use the credentials contact the developer at emmanuelle@nada.computer (sensitive data).
You can still set environment variables if you need using the dotenv gem.
rails db:create db:migrate db:seed
Using the command line:
heroku git:remote -a time-planet
Start rails server :
rails s
Start sidekiq to enable background processing
sidekiq
There is an Heroku pipeline in place with an integration with Github. So when there is a new commit merged in master
branch it is automatically pushed on staging app.
Staging is protected by basic auth to avoid duplicated content penalties with google.
Username: user
, password: password
To deploy from staging to production once the features has been tested on staging, there is a button
Promote to production
on heroku pipeline webapp.
When we make a new release to production we need to publish the changes list in the slack channel #releases to inform keepers about the changes. You can consult the last commit that has been pushed to production on production app within heroku's pipeline. With a git log in your terminal you can then know which new commits will be promoted to production.
Be careful when deploying, always add new environment variables to Heroku before deploying.
There are tasks to replicate data from production db and S3 bucket in local to be able to work with real data. To use them you'll need to have awscli installed.
Install awscli
brew install awscli
Launch task
rails replicate:prod_to_dev
This project uses rubocop with a configuration taken from standard
To check your code style :
bundle exec rubocop
A default call to action is defined for contents using variable default_cta_id
contained in credentials. You can define
an environment variable DEFAULT_CTA_ID
to override it.
All contents that are saved in database (Content, Category, Tag, Badge, Role, ...) are translated using :jsonb
backend of mobility gem. As the backend's name suggests, model's attributes
that needs to be translated are stored in jsonb column with one key-value pair for each locale. For example if we have
a title attribute on a model translated in multiple languages, the hash that will be saved in db for this column will
look like this:
{
"en": "Content's title",
"fr": "Titre du contenu",
"it": "Titolo del contenuto"
}
Mobility gem handles all the work to let us set and get attributes as usual :
I18n.locale = :fr
content = Content.new
content.title = "Le titre de mon article"
content.save
content.title #=> "Le titre de mon article"
I18n.locale = :en
content.title #=> "Le titre de mon article" (fallback to :fr locale)
content.title(fallback: false) #=> nil
content.title = "Content's title"
content.save
content.title #=> "Content's title"
See mobility documentation for more detailed information on how the gem works
For static contents we use Rails built-in I18n but we added a different backend using
I18n-active-record gem. This gem allows us to save translation keys
in db. This allows admin users to have access to them and to translate them in Active Admin back-office.
Translations are saved in translations
table. Each translation has a locale and a key attributes that allow us
to target it when we want to use it and a value that is going to be displayed.
When we use I18n.translate
it will first look for the key in db and if it can't find it, it will fallback
for the key present in yml files.
As developers when we need to create a new translation key, we create it in yml files first, then we have a rake task to save them in database when it has been pushed to production. This rake task needs to be called with arguments so the syntax is a little different. For example is the yml files looks like this:
---
fr:
home:
title: "We are the last generation that can save the planet."
subtitle: "The way we use our money, defines the world we want to live in."
The rake task to save the home title and subtitle in db should be called like this:
rails translations:load_yml_files
This rake will go through all yml files and add all translation keys. It won't create a new translation in db if there is already one with the same key in db. It will delete keys from db that are no longer present in yml files.
- Add new locale in available locales in
config/application.rb
- Create a yml file for the new locale in
config/locales/routes/
This yml file should contain all translations of translated urls. For now these translations should be found in this spreadsheet - Copy the meta image translated in the requested locale in the directory
app/assets/images/meta_images
- Once the new locale is in production, it is preferable to translate quickly following translation key:
common.flag
that is used to display a flag for the locale (used inapp/views/shared/_language_switcher.html.erb
). You can find circular flag codes on icons8common.language
that is used to display the language's name in the locale (Français for fr, or English for en). It might be better to check with the translator that the translation is ok especially if we're not able to understand that language
You can check this PR as an example of what to do to add a locale.
For now we usually add the locale in the system first. Wait for the translators to add all necessary translations in
the back office. When we consider the locale ready to make it public, we can add it in the language switcher
app/views/shared/_language_switcher.html.erb
When you want to add some code, you create a new branch from the branch master
or any other branch with :
git checkout -b $name-of-the-new-branch
The branch name should start with a prefix suggesting what kind of PR it will be :
feat
for a new feature or part of a new featurefix
for a bug fixdesign
when there will only be some front integration (a new page would probably be prefixed with feat)chore
when it will only add configuration, upgrade gems, add some documentation ... So for example a branch name should look like :feat/add-home-page
You should regularly commit (git commit -m "name of your commit"
) and push your code to github even if you don't open a PR to be sure that even if your computer crash,
you will not loose your code.
When you think you're done with what you wanted to achieve, you can push your code (git push
) and open a PR on Github.
Someone will review your code, probably make some comments and ask for modifications.
Ideally a PR should be small enough to make it easily reviewable. More than 600 line changes starts to get big.
When you need to do some modifications, you checkout your branch (git chechout $name-of-your-branch
),
make the requested changes, make a new commit and push your new code.
As you commited your changes in a new commit or multiple commits you don't need to do a git push -f
or git push --force
!! and the reviewer will easily be able to see the changes you added by consulting
only the commits you added.
If at some point in the review process, github is telling you that your branch is out of date with the base branch or that your branch has conflict with the base branch :
- You checkout your branch
git chechout $name-of-your-branch
- You fetch all data that git needs from remote repository with
git fetch
- Then you merge master into your branch with
git merger origin/master
- At this point, if you have conflict, git will stop the merge process to allow you to resolve the conflicts. Git will indicate the files where there are conflicts, so you can go in the code to resolve them.
- When this is done you can tell git to continue with
git merge --continue
- Then push your branch to the remote repository with a simple
git push
The reviewer will not be able to review your code as soon as you push it. So if you need the code of a PR you already opened to continue your work (for example you added a new model and now you will do a second PR to add a controller and views) you can checkout the branch of the first PR and then create a new branch from this one with the same command than above so for example:
git checkout feat/added-new-modal
git checkout -b feat/add-controller-and-views
Then follow the same process than explained above.
If at some point you do some requested modifications on your first PR and you need them in your second one you can do merge your first branch in the second one with the same process than before so with our example:
git checkout feat/add-controller-and-views
git merge feat/added-new-modal
if you don't have conflict then you're done but if you do resolve them and then
git merge --continue
When your PR is approved by the reviewer, we do a Squash and Merge
in Github. When you click on
Squash and merge, Github will open a window to make you choose the name of the commit and the description.
So if needed you can change the name of the commit before confirming and you should copy the url of the PR and paste it
in the description input. Then you can confirm.
PgHero is setup to capture statistics about database queries. It can allow us to get information about slowest queries for example.
It can also tell which indexes are not used or suggest other indexes to add to improve performances.
To access data you have to be logged in as admin user and then visit /pghero
Data stored by PgHero can get big so it's a good idea to clear the table from time to time with
PgHero.clean_query_stats