Having Multiple Instances of a Model in an Associated Record

I had a model that required two different User records associated with it. A Classroom model that had one User that was a student, and another User was the teacher (for each record).

classroom.rb

  belongs_to :teacher, class_name: 'User'
  belongs_to :student, class_name: 'User'
  belongs_to :user, class_name: 'User'

user.rb

has_many :classes, as: :teacher, class_name: 'Classroom'
has_many :courses, as: :student, class_name: 'Classroom'

Whitelist in controller:

params.permit(:teacher_id, :student_id)

Rails Assertions List

I’ve partial lists of test assertions and examples, but I want to document one foe myself.

# check that a user is redirected to a certain place
assert_redirected_to account_path(@account)

# check that one value is contained in another
assert_includes @account.account_users.pluck(:user_id), user.id

# check that there’s an h1 tag with text equal to @account.name
assert_select “h1”, @account.name

# check that the this text isn’t present (within a h4 tag)
assert_select “h4”, {count: 0, text: “Different Account”}

# check that a count is decreased by 1 after the delete action
assert_difference “@account.account_users.count”, -1 do        
delete account_account_user_path(@account, user.id)      
end

# check if something is true
assert account_user.reload.admin?

Validating File Types with ActionText and ActiveStorage

In my latest Rails app, I’ve started using ActiveStorage and ActionText. Previously, I always used the Paperclip gem for attachments.

With the changes in attachment storage, I needed to learn how to do validations to make sure that users weren’t uploading potential harmful files.

I’m using Trix to allow users to create rich content. Thanks to Saeloin Blog, I found JS that would help validate the file type (see the post for more).

Here’s what I did based on Saeloin Blog’s post.

(1) I created a new file in app/javascript/src/trix-editor-overrides.js

// Limits the file types that can be uploaded in ActionText
// https://blog.saeloun.com/2019/11/12/attachments-in-action-text-rails-6.html

window.addEventListener("trix-file-accept", function(event) {  
const acceptedTypes = ['image/jpeg', 'image/png']  if (!acceptedTypes.includes(event.file.type)) {    event.preventDefault()    alert("Only jpeg or png files can be uploaded")  
}})

(2) I added this line in application.js:

import "src/trix-editor-overrides"

For Active Storage, I used the Active Storage Validations gem, and in my model files, I added:

  validates :image, attached: true,
                    content_type: ['image/png', 'image/jpg']

Editing credentials.yml.enc on Windows

Since credentials.yml.enc is encrypted, you have to edit it in a different way than most Rails files.

To open and edit it Windows, you have to assign an editor, and then open the file via console.

(1) In the console, assign the editor:

set EDITOR=notepad

(2) Next, edit the file

rails credentials:edit

(3) Save the notepad file and close

If you have different files for each environment in the credentials directory, you can edit it with:

rails credentials:edit -e development

How Do I Make Facebook Comments Load with Turbolinks?

I installed Facebook’s Comments plug-in on my site and found that it worked immediately except for one problem. To get it to show on a page, the page had to be reloaded because of Turbolinks. I was able to fix this using Coffeescript with the help of this Stack Overflow post.

Here’s I fixed it:

(1) Created a new file assets/javascripts/fb_turbolinks_fix.js.coffee (replace the values in italics based on the Connect URL Facebook provides you in its code):

$ ->
loadFacebookSDK()
bindFacebookEvents() unless window.fbEventsBound

bindFacebookEvents = ->
$(document)
.on(‘page:fetch’, saveFacebookRoot)
.on(‘page:change’, restoreFacebookRoot)
.on(‘page:load’, ->
FB.XFBML.parse()
)
@fbEventsBound = true

saveFacebookRoot = ->
if $(‘#fb-root’).length
@fbRoot = $(‘#fb-root’).detach()

restoreFacebookRoot = ->
if @fbRoot?
if $(‘#fb-root’).length
$(‘#fb-root’).replaceWith @fbRoot
else
$(‘body’).append @fbRoot

loadFacebookSDK = ->
window.fbAsyncInit = initializeFacebookSDK
$.getScript(“//connect.facebook.net/en_US/sdk.js”)

initializeFacebookSDK = ->
FB.init
appId : # put your app ID
autoLogAppEvents : true
xfbml : true
version: ‘v5.0’

(2) In application.js make sure to include the file (before Turbolinks):

//= require fb_turbolinks_fix

(3) In your view, include this:

<div id="fb-root"></div>
<div class="fb-comments" data-href="https://developers.facebook.com/docs/plugins/comments#configurator" data-width="" data-numposts="5"></div>

How Do I Add a WordPress Blog to My Rails App?

I wanted to have a robust blog for my Rails app, but I didn’t want to spend too much time on it. Initially I created a simple model (Articles) and added TinyMCE in it, but I ran into some challenges in how photos were displaying, and other styling aspects. I could’ve spent more time on it, but it was starting into eating into the time I was spending on developing enhancements to the app itself.

You can easily create a WordPress instance and map it to a subdomain. For example, blog.foo.com.

The problem with that, as discussed by SEO experts, Moz.com, is that it can hurt your search engine optimization efforts (SEO). Instead, it’s better to use a subdirectory like: foo.com/blog.

I was able to set-up my blog this way with the help of Dipesh Batheja’s article.

Here’s the exact steps I took:

(1) Added the domain (foo.com) to a WordPress hosting account on Siteground (my host)

(2) Using cPanel on Siteground, I created a subdomain, ‘blog’ for my domain (so I now could use blog.foo.com)

(3) In cPanel, I used “Let’s Encrypt” to add an SSL certificate to my subdomain (now I could use httpS://blog.foo.com)

(4) Installed WordPress (in cPanel) to my subdomain

(5) I went to my DNS records and added two A records – http://www.blog.foo.com, and blog.foo.com, each pointing to the IP address of my domain on Siteground. After the DNS propagated, I could go to the URL https://blog.foo.com and see my WordPress instance.

(6) In my Rails app, I added the Rack Reverse Proxy gem to my gemfile:

gem "rack-reverse-proxy", require: "rack/reverse_proxy"

(7) ‘bundle update’ to get the gem installed

(8) In config/application.rb, I added this:

config.middleware.insert(0, Rack::ReverseProxy) do 
  reverse_proxy_options force_ssl: true, replace_response_host: true

   reverse_proxy(/^\/blog(\/.*)$/, 'https://blog.foo.com$1', opts = { preserve_host: true })
end

(9) In routes.rb, I added this route:

get "/blog", to: redirect('https://www.foo.com/blog/', status: 301)

(10) In WordPress, in General Settings, I set:

WordPress Address (URL): https://blog.foo.com/

Site Address (URL): https://www.foo.com/blog (I’ve found that when I want to change a post, I need to change this temporarily to https://blog.foo.com/)

Now, every time someone goes to foo.com/blog, they’re redirected to my WordPress blog, and my SEO isn’t hurt.