Home > Enterprise >  Associations in Rails for a basic Books app?
Associations in Rails for a basic Books app?

Time:04-16

I am making a basic app for the growing incel online community linking them to various pieces of literature they could find useful, helpful and guiding. I am having difficulty creating proper associations.

I have several models:

  1. User: user.rb, a model of a user to view, comment and like books.
  2. like: like.rb, like model to assign likes to books.
  3. comment: comment.rb, comment model to comment on book models (via a user).
  4. book: book.rb, model for books, will route/view pdf's to host server.
  5. bookshares: book_share.rb, will be a join table linking users to likes to comments to books and so on and vice versa.
  6. godmodel: hypothetical model not yet implemented to link together everything in an all encompassing manner.

So, I want users to be able to be create with a username and be able to view, like and comment books on the 'website' that will eventually be migrated over to a android app. Here is my abysmal code:

class BookShare < ApplicationRecord
    
    validates :book_id, presence: true, uniqueness: true
    validates :viewer_id, presence: true, uniqueness: true 
    
    belongs_to :user 
    belongs_to :book
    belongs_to :comment
end
class Book < ApplicationRecord

    validates :title, presence: true 
    validates :author, presence: true 
    validates :user_id, presence: true 
    validates :isbn, presence:  true 
    validates :title, presence: true 

    has_many :book_shares
    has_many :users, through: :book_shares
    has_many :likes, through: :book_shares
    has_many :comments, through: :book_shares
end
class Comment < ApplicationRecord
    
    validates :user_id, presence: true, uniqueness: true
    validates :book_id, presence: true, uniqueness: true 
    validates :title, presence: true 

    has_many :book_shares
    has_many :books, through: :book_shares
    
end 
class GodModel < ApplicationRecord
    has_many :books 
    has_many :users
    has_many :comments 
    #has_many :likes 
    has_many :topics 
    has_many :book_shares
end
class Like < ApplicationRecord
    # not fully implemented yet. 
    validates :user_id, presence: true 
    
    belongs_to :user 
end
class User < ApplicationRecord
    validates :username, presence: true, uniqueness: true

    has_many :book_shares
    has_many :comments, through: :book_shares
    has_many :books, through: :book_shares

end
class Topic < ApplicationRecord
   # not implemented yet 
end

Here is my schema:

ActiveRecord::Schema[7.0].define(version: 2022_04_12_145402) do
  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "book_shares", force: :cascade do |t|
    t.integer "book_id", null: false
    t.integer "viewer_id", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["book_id", "viewer_id"], name: "index_book_shares_on_book_id_and_viewer_id", unique: true
    t.index ["book_id"], name: "index_book_shares_on_book_id"
    t.index ["viewer_id"], name: "index_book_shares_on_viewer_id"
  end

  create_table "books", force: :cascade do |t|
    t.string "title", null: false
    t.string "author", null: false
    t.integer "user_id", null: false
    t.text "body_info"
    t.integer "isbn", null: false
    t.binary "photo"
    t.binary "r_data"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["user_id"], name: "index_books_on_user_id"
  end

  create_table "comments", force: :cascade do |t|
    t.integer "user_id", null: false
    t.integer "book_id", null: false
    t.text "body_txt"
    t.string "title"
    t.binary "photo"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["book_id"], name: "index_comments_on_book_id"
    t.index ["user_id"], name: "index_comments_on_user_id"
  end

  create_table "god_models", force: :cascade do |t|
    t.string "title"
    t.integer "user_id"
    t.integer "comment_id"
    t.integer "book_share_id"
    t.integer "book_id"
    t.integer "like"
    t.integer "topic"
    t.binary "data_x"
    t.date "today"
    t.binary "title2"
    t.boolean "nullfy"
    t.float "nums"
    t.text "body"
    t.datetime "create_at_"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["body"], name: "index_god_models_on_body"
    t.index ["book_id"], name: "index_god_models_on_book_id"
    t.index ["book_share_id"], name: "index_god_models_on_book_share_id"
    t.index ["comment_id"], name: "index_god_models_on_comment_id"
    t.index ["data_x"], name: "index_god_models_on_data_x"
    t.index ["like"], name: "index_god_models_on_like"
    t.index ["nullfy"], name: "index_god_models_on_nullfy"
    t.index ["nums"], name: "index_god_models_on_nums"
    t.index ["title2"], name: "index_god_models_on_title2"
    t.index ["today"], name: "index_god_models_on_today"
    t.index ["topic"], name: "index_god_models_on_topic"
    t.index ["user_id"], name: "index_god_models_on_user_id"
  end

  create_table "likes", force: :cascade do |t|
    t.integer "user_id"
    t.string "likeable_type"
    t.bigint "likeable_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["likeable_type", "likeable_id"], name: "index_likes_on_likeable"
    t.index ["user_id", "likeable_type", "likeable_id"], name: "index_likes_on_user_id_and_likeable_type_and_likeable_id", unique: true
  end

  create_table "users", force: :cascade do |t|
    t.string "username", null: false
    t.string "email"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["username"], name: "index_users_on_username", unique: true
  end

end

Example controller:

class UsersController < ApplicationController
    
    def index 
        render plain: 'index' 
    end

    def show 
        render plain: 'show'
    end

    def new 
        render plain: 'new'
    end

    def destroy 
        render plain: 'destroy'
    end

    def update 
        redner update: 'update'
    end

    private 
        def usershare_param 
            params.require(:user).permit(:username)
        end
end

This is what I produced so far. I am able to create the model object, save them I think and populate their fields but I don't think my models are working with the given associations.

I tried using erd but it does not work. Given the use of my app is the models/associations correctly made? I want to have a user who can view/comment/like books of interest. A book can have many likes and comments, books can be viewed by many users, users can like and comment many books, topics will be implemented later to assort the books. The entire mechanism of liking/commenting/viewing via a user(s) will be implemented via a joins table called bookshares. I want to write my associations correctly before moving onto the view/routes part of the mini-protect.

CodePudding user response:

With 4 tables, books, users, comments and likes. You can implement the given design.

a book can have many likers(users), a user can like many books, forms many-to-many relationship between users and books. Make likes a join table.

Similarly, a book has many comments, a user can write many comments. Make comments a join table between users and books with extra fields specific to comment.

    # app/models/book.rb

    has_many :likes, dependent: :destroy 
    has_many :comments, dependent: :destroy 
    has_many :lovers, through: :likes, source: :user
    has_many :commentors, through: :comments, source: :user
    # app/models/user.rb
    has_many :likes, dependent: :destroy
    has_many :comments, dependent: :destroy
    has_many :fav_books, through: :likes, source: :book
    # app/models/like.rb
    belongs_to :book
    belongs_to :user 
    # app/models/comment.rb
    belongs_to :book 
    belongs_to :user

You can consult this guide to explore topics in more depth.

  • Related