Building a constrained-input forum with Rails

For a toy project to evaluate Rails against lighter-weight stacks, the goal was a forum where users interact without free-text input. The workaround: a refrigerator poetry board, where poems are assembled by dragging from a fixed word set. The constraint sidesteps spam and moderation while still exercising real user-generated content.

Drag-and-drop without the JavaScript burden

Rather than hand-rolling drag behavior, jQuery UI’s draggable provides it almost for free. The one catch was mobile support, which required jQuery UI Touch Punch — a small patch that makes the library respond to touch events. The demo words (banana, forest, cake, is) drag fine on desktop and mobile after the fix.

Active Record associations

The forum’s data model has three resources: users, topics (the obvious name “threads” is a reserved word in Rails), and posts. Rendering a post means showing its author’s username, which naively suggests loading every user per post individually:

@posts = Post.where(topic_id: id)
@posts.each do |post|
    user = User.find(post.user_id)
    post.user = user
end

That approach issues one SQL query per post, which is wasteful. Rails’ associations solve this by declaring relationships in the models:

  1. Add has_many :posts to the User model.
  2. Add belongs_to :user to the Post model.
  3. Declare the analogous UserTopic relationship and give Topic a has_many :posts.

Rails infers the join column from convention — the user_id column in posts is named exactly as expected, so no join configuration is needed. Fetching every post with its user collapses to a single line:

@posts = @topic.posts.order(created_at: :asc).preload(:user)

Beyond brevity, this loads all users in one query rather than one per post. Rails offers several flavors of this — preload, eager_load, joins, and includes — which behave differently under the hood, though they remain a topic for later.

Scaffolding and migrations from the CLI

Adding a full Topic model and controller with basic CRUD endpoints is a one-command operation:

rails generate scaffold Topic title:text

The generated controller gives working create, edit, and delete actions immediately. What came back was mostly usable as a starting point — expected to be trimmed down, but far easier than placing each piece of boilerplate by hand.

The rails tool also generates database migrations from the command line. Removing the title column from posts required only:

rails generate migration RemoveTitleFromPosts title:string
rails db:migrate

Rerunning migrations as the schema changed was straightforward. One snag: adding a not null constraint failed where existing rows already had NULL values in that column. Fixing the offending records and rerunning the migration resolved it cleanly.

The project continues — next step is putting it online.