Diary ruby on rails getting started
One am working on learning Ruby on Rails currently, and there are some problems that are met. This post serves as a diary to conclude what errors are being made, and how they are solved. We might or might not include the thought process of solving them, and they might or might not include the only method to solve, and some might or might not be necessary to solve the problem.
Syntax error: expecting do or ‘{‘ or ‘(‘
This happens in the article.rb
. Originally we have the code:
class Article < ApplicationRecord
validates :title, presence :title, length: {minimum: 5}
end
And it gives error. However, the question is solved here in this article. Particularly, the colon before true must stick to presence rather than stick to true, presence: true
than presence :true
.
Destroy not working
The first thing after the CRUD, we have the Destroy link not working. Particularly, we tried quite a number of stuffs, especially we make comparison with the rails generate scaffold ...
and copy and paste one by one and see what they gives.
We changed things in the articles_controller.rb
to support json file for delete
and create
but to no avail. The thing still doesn’t change much. Finally, only when we changed our show.html.erb
file to some other things then only it’s solved. Particularly, we moved the destroy outside into their own dividers rather than inside the list.
Before:
<h1><%= @article.title %></h1>
<p><%= @article.body %></p>
<ul>
<li><%= link_to "Edit", edit_article_path(@article) %></li>
<li><%= link_to "Destroy", @article ,
method: :delete,
data: { confirm: 'Are you sure?' } %></li>
<li><%= link_to "Home", root_path %></li>
</ul>
After:
<h1><%= @article.title %></h1>
<p><%= @article.body %></p>
<ul>
<li><%= link_to "Edit", edit_article_path(@article) %></li>
<li><%= link_to "Home", root_path %></li>
</ul>
<div>
<%= button_to "Destroy", @article ,
method: :delete,
form: {
data: { turbo_confirm: 'Are you sure?' }
}
%>
</div>
The confirmation, based on this tweet, changes too!
And why it works when moving out of the list? One have no idea. It just works. You could also try to use link_to
instead of button_to
in the latter ones, it might work as well, one aren’t sure about that. Basically it looks more like just how to display it. You can also use button_to
in the non-working ones, and it also display a button, and it still doesn’t work until you move it out.
Where do partials go
the .html.erb
files don’t necessarily always go into the same folder, but they are in the same grandparent folder. So for example, comments don’t go into the usual article folder, but they go into the comments folder. And also check whether the naming is correct, particularly add or remove an ‘s’ from the erb file.
Cannot add or delete comments
There are nothing specific arises, but if you check the log of rails server
, you found 404 not found.
Particularly, that’s because we have some errors (not the tutorial, but when one type it in) with app/controllers/comments_controller.rb
).
Instead of this:
@article = Article.find(params[:article_id])
we have this:
@article = Article.find(params[:id])
We need to fetch in the correct id for it to work. Or else, we cannot delete or create.
Bootstrap
Bootstrap is different from Rails 6. First, you need ruby v3 which cannot be installed with normal sudo, but requires rvm to do the work. If you type rvm use ruby-3.0.3
it will tell you the command to. Then, you can continue with this video for tutorial.
Though you can add css bootstrap to current files, it might fail. As one did, it fails with yarn build:css
NoMethodError. So there are two ways to solve the problem: one is rebuilding from the beginning using rails new name_of_project --css=bootstrap
, another being manually add the build:css
function to package.json
. The command will require you to run rails new some_name --css=bootstrap
, copy the package.json build:css command from there, delete that project, then paste to the package.json you have. (As of rails v7.0.2.3). In the future, this might not require if they discover the bug and fix it.
The former is using Turbo, the latter uses importmap. So that’s the difference.
If you are looking at Michael Hartl v6 tutorial (not the most current, but the book from archive which is quite old), there are some problem with the bootstrap. Specifically, the bootstrap I think it changes, so some classes no longer available. For example this:
<header class="navbar navbar-fixed-top navbar-inverse">
<div class="container">
<%= link_to "sample_app", '#', id: "logo" %>
<nav>
<ul class="nav navbar-nav navbar-right me-auto mb-2 mb-lg-0">
<li class="nav-item"><%= link_to "Home", '#' %></li>
<li class="nav-item"><%= link_to "Help", '#' %></li>
<li class="nav-item"><%= link_to "Log in", '#' %></li>
</ul>
</nav>
</div>
</header>
This no longer works. First, navbar-inverse
is not even a class anymore, it’s replaced with navbar-dark bg-dark
. Etc. When one complete the migration one will make changes here (which one haven’t yet). One guesses its Bootstrap 4 above, and we require updating to Bootstrap 5, hence class changes.
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<%= link_to"sample_app", '#', class: "navbar-brand", id: "logo" %>
<div class="collapse navbar-collapse" id="navbarSupportedContent"></div>
<ul class="nav navbar-nav navbar-right me-auto mb-2 mb-lg-0">
<li class="nav-item"><%= link_to "Home", '#', class: "nav-link active"%></li>
<li class="nav-item"><%= link_to "Help", '#', class: "nav-link active" %></li>
<li class="nav-item"><%= link_to "Log in", '#', class: "nav-link active" %></li>
</ul>
</div>
</div>
</nav>
ERb requires class before id
Make sure to put class before id when using ERb. Let’s see an example:
<%= link_to"sample_app", '#', class: "navbar-brand", id: "logo" %>
will work, but if you go the other way round, it won’t. Compilation will fail (at least that’s what one encounters. If it changes in the future, please do tell me, thanks!)
SCSS coloring
Because we want the container to have a gray background, we made a CSS for it in the application.bootstrap.scss
. However, one tested it and doesn’t work. (The test is not extensive, it may be one inserting the wrong command, because css requires rebuilding with a series of commands which one tested in parallel and only come to conclusion at the end of testing this too, so that may be a reason why it doesn’t built).
The solution being put in another scss file and import it into application.bootstrap.scss
.
Another being the background color, we couldn’t use common colors like white
, orange
, it doesn’t seem to work. It may be because one put the !important
tag, but it may be not. Whatever the reason is, the solution is to use background-color: rgba(128, 128, 128, 0.1) !important;
that kind of definition for example, example for light-gray background.
Wrong migration?
We did something wrong. Migration of database done on heroku, then we realize upload wrong, requires remigration. However, one of the migration is a conflicting migration we need to delete. If we don’t, we have to push to heroku, rollback, then change branch re-push to heroku, then migrate up again. Ok with that?
If not, another way is to destroy the database (it may work with reset, one don’t know) by going to your heroku webpage, then click on app name, check for postgresql, open it up in new page, destroy database. After destroy, recreate it. Then, run heroku run rails db:migrate
. Voilà!
Styling link_to
When you loop through a link_to
, you can add the class there, and everything that’s wrap inside don’t need manual declaration of class. For the CSS, you can just make one single class.
.article {
color: #000;
text-decoration: none;
div {
background-color: #eee;
}
ul {
list-style-type: none;
display: flex;
justify-content: center;
flex-direction: column;
}
li {
border: 1px solid green;
background-color: rgba(127, 127, 127, 0.075) !important;
border-right: -3em;
&:hover {
background-color: rgba(250, 190, 88, 0.35) !important;
}
}
}
Note there are some we put at the top-level scss. These are those that make changes to the link_to
directly. Previously if you’re in a
, you would put it in there, but that cannot change link_to
directly. Every single class inside will be overwritten with link_to
class, wherever it wraps till the “end” tag. If you define another class for say the p
element, it won’t work. You must put the p
related to article
for it to work.
Then the ERb:
<%= link_to article[:target], class: "article" do %>
<ul>
<li>
<h4><%= article[:title] %></h4>
<p><%= article[:explanation] %></p>
</li>
</ul>
<% end %>
Turbo Error with Forms
There’s an error with forms discussed here: https://github.com/hotwired/turbo-rails/issues/12. However, the method discuss there does work when we have an errors and use render 'new'
with a POST request. However, it fails if we want to redirect_to @user
page because it’s a GET request instead. What we need is to deactivate turbo. The solution is here
Just change your form:
<%= form_with model: @user, local: true, data: { turbo: false } do |f| %>
...
<% end %>
Note the turbo: false
part.
has-error
bootstrap
That has deprecated on v3; so we know that the course one is looking at is using Bootstrap v3. Rather, now we don’t need to override the .field_with_errors
anymore for .has-error
.
Anyways; we don’t need to anything; plus it uses .is-invalid
nowadays and there are form-control.is-invalid
already in place for red text. No override is needed.
Integration test error
The usual integration test assert_difference
(and assert_no_difference
) have this:
post users_path, params: { user: ...}
Problem is the comma between users_path
and params
. Upon removal of that comma, things works!
Database postgresql production error
If you follow M Hartl book, there they determine the database with some name; however that’s not true; we also don’t have the specific environment variable as such, only one DATABASE_URL. Hence, we need to extract data into that.
First, in config
, we create config/database_helper.rb
and include the following class:
class String
def string_between marker1, marker2
self[/#{Regexp.escape(marker1)}(.*?)#{Regexp.escape(marker2)}/m, 1]
end
end
This is use for string extraction. Then, in the config/database.yml
, add the following:
<% require_relative 'database_helper' %>
<% @db_url = ENV['DATABASE_URL'] %> # to shorten the name
...
production:
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
database: <%= @db_url.split('/').last if @db_url %>
username: <%= @db_url.string_between("postgres://", ":") if @db_url %>
password: <%= @db_url.string_between(":", "@").partition(":").last if @db_url %>
This allow us to connect to the correct database, not hanging around hence having some 500 Internal Server Error that doesn’t explain itself (which is actually due to connection with database not established).
Note: We added
if @db_url
at the end of each, because if it don’t, it’ll run during other times likerails test
and things cannot continue running normally. We only want it to be assigned if it’s available (in Heroku); otherwise we don’t assign it. This is somewhat hardcoding, but it doesn’t matter. We will only use postgresql. If we need others like mysql, we’ll make changes again then. Don’t think too far!
Debug information pretty print
If you want it red wordings, we could do simple_format
, such as this:
<%= simple_format debug(params).to_yaml if Rails.env.development? %>
If you want it beautifully formatted, we should consider using pp
like this:
<%= pp debug(params.to_unsafe_h) if Rails.env.development? %>
If you don’t mind red wordings, you can also do this:
<%= simple_format debug(params.to_unsafe_h).to_yaml if Rails.env.development? %>
How to know what parameters we see?
Easiest is just at the controller, make render 'new'
. This allows after typing in something to the form, it’ll reload the page with the params
, then we know what are available in the params
to pass to Rails backend.
Be careful with routes
When you do get
or post
, be careful of where it routes to. Usually, post
goes to name#create
; don’t put name#new
instead!.
Log in, Log out
When we logged in, we expect quitting the browser to forget; but no, Rails 7 have cookies on by default! WE can see this by checking the session
info.
In application.html.erb:
<%= simple_format debug(session).to_yaml if Rails.env.development? %>
Checking below, we see something like:
@delegate={..., "user_id"=>...}
even after closing and re-opening the browser, stating that cookies are enabled by default! Hence, the user logout method won’t work.
For Rails 7, due to Turbo, we cannot use method: :delete
for DELETE request, it’ll become GET request. Just to fix, use this instead:
<%= link_to "Log out", logout_path, data: { "turbo-method": :delete}, class: "dropdown-item" %>
With the turbo-method
, we can fix this. Check this out
Then, we also need to fill in our log out. Ensure to redirect to the correct page after logout is also required.
In sessions_controller.rb:
def destroy
log_out
redirect_to root_path, status: :see_other
end
We need the status: :see_other
, check this out.
Our log_out
is a function, in sessions_helper.rb
:
def log_out
session[:user_id] = nil
end
This invalidates the logout successfully.
On the design dropdown
Lots of the information are available on bootstrap dropdown page, so ensure you migrate.
Particularly, divider
class is now dropdown-divider
, and don’t forget nav-item
on each object (excluding the divider
).
Responsive Design Mode
In Brave Browser, the responsive design mode is Ctrl+Shift+m when the developer console is open (which you can open with F12 or Ctrl+Shift+i).
Mobile View Errors
Logo
The first thing missing is the Logo. That’s because of our div
class tag, we added collapse
. Removing it will reappear.
<!-- From this -->
<div class="collapse navbar-collapse">
</div>
<!-- To this -->
<div class="navbar-collapse">
</div>
But we could just remove it totally.
Hamburger Menu
There’s one styling where we couldn’t get the navbar icon on the right. So, we could just copy from this page and see the difference.
Particularly in one’s case, it’s because the button
contains class = "navbar-collapse"
, which shouldn’t be. With navbar-collapse
, not only mobile menu have the toggler button below the logo, when we expanded to
desktop page, the icon also doesn’t go missing (which is not intended). Removing that navbar-collapse
solves everything!
Looking for Javascript?
If we try to use a create.js.erb
with def create
in our controller, the form requires to send an Ajax request, which is only true if remote option is set to true. Otherwise, it won’t react.
Heroku?
If you ever accidentally delete the remote of heroku for whatever stupid reason found online, you can init back from the “deploy” page on dashboard. Basically, create a fresh new undeployed app then:
cd my_project
(git init)
heroku git:remote -a heroku-app-name
Pagination
On the book, the old gem is no longer usable. Here, we shall use the new gem that supports Bootstrap v5. This is the gem
In your GemFile:
gem 'will_paginate-bootstrap-style'
Then, run:
bundle install
bash rebuild.sh
We need to rebuild to update the css file. Then, just follow the instruction in the page link:
<%= will_paginate @users, renderer: WillPaginate::ActionView::BootstrapLinkRenderer %>
Integration Test Fixtures
When on try to use a different entry, it failed. Test that uses the first entry passes, but changed to another entry failed. At first, one thought this might be problem of ERb, but it’s not. It’s something else. One checked the database from Rails console and everything works fine!
Reason is, we forgot to insert the username
. Let’s test why it fails without username;
After test, although we enable log to console, it’s still too difficult to find out why. In fact, we did not know why it fails without.
Therefore, a username
must exist for the program to work. If it doesn’t, it won’t work. Therefore, username
cannot be nil
.
createPopper.js process
is not defined.
We know that Rails environment doesn’t use “process.env”, so it’s annoying when you try to make a dropdown outside of navbar that it calls this. Hence, the quick fix is: In application.html.erb <head>
part, add this:
<script>window.process = { env: {} }</script>
Reference: https://github.com/rails/importmap-rails/issues/65
Why Custom Class Function Not Running?
When one was programming, one changes the custom class function from this:
class CustomClass
def self.custom_fn(input1)
end
end
into this:
class CustomClass
def self.custom_fn(input1, input2)
end
end
What it gives error is “wrong number of arguments, expected 1 but given 2”.
That’s because we need to restart rails server, and/or rebuild then only things will be updated. Thing is, it’s imported at the beginning and only at the beginning using a require
, hence to update it, it won’t work with live updates, but you need to restart it.
It’s just the same when you update CSS or JS functions. These are also precompiled, nothing adjoint to rails but imported, so you need to restart/rebuild upon changes.
Then things run as expected.
Ruby not getting the correct version with RVM?
If you ever use rails without it as the home directory, you know that everytime you enter the folder, running rails
command fails. Particularly, this is partially due to we need to first have them install and initiated the first time we git clone
them.
Really, it’s also caused by the ruby version that doesn’t get compatible with your Gemfile
.
To solve this, check for the file .ruby-version
in your rails folder (top directory) and change from system
to the specific version in your Gemfile
, and everytime you enter the directory, it’ll now be the correct ruby version. Voilà, solved!