Early construction

As previously discussed, I am currently in the process of remaking Bicker with modern technologies and architecture, hopefully along with lessons learned over the last decade about what makes a good community system. In the interest of transparency, I’m using the blog as a kind of developer journal while I work, posting occasional updates as to where things stand.

The Skeleton

A few days ago, I created the new Ruby on Rails project to work with, obviously, from the terminal…

rails new Bicker

And I created a public git repository for the project, moved the contents of the project in, and wrote a new README file to actually explain the project, rather than the default Rails file that is a message to developers.

…an excuse to link to the repository…

That’s presumably all completely obvious and barely worth mentioning, for most readers, but is still worth going through all the boring steps, in case anybody needs or wants to follow along. Plus, it furnishes an excuse to link to the repository, in case anybody wants to contribute as we go. It would, after all, make me very happy for this project to not be a one-man show.

Basic Model

Having been here before, I already have a decent sense of the database models we’ll need. We end up with something like the following, if you get excited about database schemas.

create_table :categories do |t|
  t.string :name, { :null => false }
  t.string :of, { :default => 'message' }
  t.references :parent, null: false, foreign_key: true
  t.timestamps
end

create_table :messages do |t|
  t.string :subject, { :null => false }
  t.integer :version, { :default => 1 }
  t.references :category, null: false, foreign_key: true, :null => false
  t.references :user, null: false, foreign_key: true, :null => false
  t.references :paragraph, null: false, foreign_key: true
  t.timestamps
end

create_table :paragraphs do |t|
  t.references :message, null: false, foreign_key: true
  t.references :parent, null: false, foreign_key: true
  t.references :next, null: false, foreign_key: true
  t.references :user, null: false, foreign_key: true
  t.text :content
  t.timestamps
end

create_table :events do |t|
  t.references :user, null: false, foreign_key: true
  t.references :message, null: false, foreign_key: true
  t.timestamps
end

create_table :tags do |t|
  t.references :user, null: false, foreign_key: true, :null => false
  t.references :paragraph, null: false, foreign_key: true, :null => false
  t.string :word, :null => false
  t.timestamps
end

create_table :sessions do |t|
  t.integer :session_id
  t.text :data
  t.timestamps
end

I’m skipping a couple of indexes and the users table, the former because it isn’t interesting, here, and the latter for reasons that will become apparent in just a few paragraphs.

If you’re not familiar with Ruby on Rails, we create these migrations by issuing something like the following at the command line:

rails generate migration Category name:string of:string parent:references

…and then manually editing the migration file in .../db/migrate/ to add the default values and non-null requirements. (I haven’t worked extensively with Rails in a while, so I have to admit that I’m the tiniest bit disappointed that things like defaults still can’t be automatically generated.)

That might turn out to be substandard in the long run, but if any of that turns out to be wrong, changing models in Rails isn’t all that difficult.

Hmmm…

The most suspect models, here, are for sessions and (as mentioned) users.

…now-erased-from-history…

I believe they’re based on the needs of the now-obsolete (it hasn’t been updated since 2011) restful-authentication and the now-erased-from-history (the two links in the README file aren’t even in the Wayback Machine) smart-session-store. It’s probably never a good sign when all evidence of a project’s existence has been scrubbed from the entire Internet, and now I wonder if I released code that drowned puppies or something horrible like that because of a rogue library.

So, I probably shouldn’t use those, this time around…especially the one that apparently never existed in this version of the timeline…

Security

Locked door

Speaking of maybe not using decade-old authentication that doesn’t exist, I should probably find a more modern solution for that.

While I’ve always liked the premise, I dismissed OAuth right out of the gate as sometimes being unfriendly to automation by requiring a manual log-in attempt. Plus, OAuth never became simple enough for people to take control of their identities, so it typically comes down to “log in through some megacorp nobody trusts or trust that our implementation doesn’t have the same huge security holes as if we did everything locally.”

…requires trusting that third-party…

Similarly, I dismissed (for now) any third-party authentication system, on the basis that it represents a potential point of failure out of anybody’s control and it requires trusting that third-party—a mostly-unknown company that could well be planning to eventually sell to someone with a track record of abusing users—with user data.

While it’s inevitably going to be less secure to handle all authentication locally, it’s cleaner in concept, for now, and can always be changed in some future version.

Because it looks to be a complete solution, I decided to go with the solution described in this Nopio blog post recommending Devise, Rolify, and CanCanCan.

As predicted, though, I jumped the gun on creating a user: Devise has its own idea of what the user should look like, so I need to remove the columns I dragged over from my initial concept.

remove_column :users, :email
remove_column :users, :crypted_password
remove_column :users, :salt
remove_column :users, :remember_token
remove_column :users, :remember_token_expires_at

Except for Rolify generating a database migration that isn’t quite valid in modern Rails—we now need to specify the Rails release the migration was written for, so a [6.0] needs to be tacked onto ActiveRecord::Migration—everything installed without complaint, so it looks to be ready to add to the yet-to-be-written Bicker application.

That’s a decent enough start for now, adding a couple of temporary links from testing already validating that it’s possible to register, log in, and log out. Next time, I should actually have something working to authenticate for!


Credits: The header image is unnamed by an anonymous PxHere photographer and is made available under the CC0 1.0 Universal Public Domain Dedication. Lock is by Bicanski and also made available under the CC0 1.0 Universal Public Domain Dedication on PIXNIO.