0

I made a app for managing personal library (books and comics) and it was working well but all of the suddent it started to show to all users (new or existing) all the books that were introduced by a given user (it seems to display the entire db); but i have devise and pundit implemented and it was protecting the user information until now.... Need some help solving this issue. Code follows but if needed some more, please shout. Thanks in advance.

Book_controller.rb

class BooksController < ApplicationController
  before_action :authenticate_user!

  def index
    unless params[:term].present?
      @books = policy_scope(Book)
    else
      @books = policy_scope(Book)
      @books = Book.search_by_full_name(params[:term])
    end
    @books = Book.order(:title)
    respond_to do |format|
      format.html
      format.csv { send_data @books.to_csv }
      format.xls # { send_data @products.to_csv(col_sep: "\t") }
    end
    @books = Book.paginate(page: params[:page])
  end

  def show
    @book = Book.find(params[:id])
    authorize @book
  end

  def new
    @user = User.find(params[:user_id])
    @book = Book.new
    authorize @book
  end

  def create
    @user = User.find(params[:user_id])
    @book = Book.new(book_params)
    @book.user = @user
    authorize @book
    if @book.save
      redirect_to user_books_path
      flash[:notice] = 'Success. Your book was added to the Library'
    else
      render "new"
      flash[:notice] = 'Book not created. Please try again'

    end
  end

  def edit
    @user = User.find(params[:user_id])
    @book = Book.find(params[:id])
    authorize @book
  end

  def update
    @book = Book.find(params[:id])
    @book.update(book_params)
    authorize @book
    redirect_to user_book_path
  end

  def destroy
    @book = Book.find(params[:id])
    @book.destroy
    authorize @book
    redirect_to user_books_path
  end

  private

  def book_params
    params.require(:book).permit(:title, :author, :photo, :comments)
  end
end

book_policy.rb

class BookPolicy < ApplicationPolicy
  class Scope < Scope
    def resolve
      scope.where(user: user)
    end

    def index?
      record.user == user
    end

    def show?
      true
    end

    def new?
      true
    end

    def create?
      true
    end

    def edit?
      true
    end

    def update?
      true
    end

    def destroy?
      record.user == user
    end

  end
end

application_policy.rb

class ApplicationPolicy
  attr_reader :user, :record

  def initialize(user, record)
    @user = user
    @record = record
  end

  def index?
    false
  end

  def show?
    true
  end

  def create?
    true
  end

  def new?
    create?
  end

  def update?
    true
  end

  def edit?
    update?
  end

  def destroy?
    true
  end

  class Scope
    attr_reader :user, :scope

    def initialize(user, scope)
      @user = user
      @scope = scope
    end

    def resolve
      scope.all
    end
  end
end

book.rb

class Book < ApplicationRecord
  belongs_to :user
  has_many :loans

  has_one_attached :photo

  validates :title, presence: true
  validates :author, presence: true

 

  include PgSearch::Model

  pg_search_scope :search_by_full_name, against: [:title, :author],
    using: {
      tsearch: {
        prefix: true
      }
    }

    def self.to_csv(options = {})
      CSV.generate(options) do |csv|
        csv << column_names
        all.each do |book|
          csv << book.attributes.values_at(*column_names)
        end
      end
    end

    self.per_page = 12

end

user.rb

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  after_create :send_welcome_email


  has_many :books
  has_many :comics
  has_many :wishlists
  has_many :loans, through: :books
  has_one_attached :photo

  private

  def send_welcome_email
    UserMailer.with(user: self).welcome.deliver_now
  end

end
Eyeslandic
  • 14,553
  • 13
  • 41
  • 54
Funk Dr
  • 31
  • 5
  • 1
    Where are you filtering for the signed in user? This just fetches everything I presume `@books = Book.paginate(page: params[:page])` – Eyeslandic May 03 '21 at 13:28

3 Answers3

0

When you reassign the @books instance variable, the previous scope is lost. Try sth like this:

    @books = policy_scope(Book).order(:title)
    @books = @books.search_by_full_name(params[:term]) if params[:term].present?
    respond_to do |format|
      format.html { @books = @books.paginate(page: params[:page]) }
      format.csv { send_data @books.to_csv }
    end
eikes
  • 4,811
  • 2
  • 31
  • 31
0

You are overwriting the @books variable many times instead of doing some chaining.

@books = policy_scope(Book)
@books = @books.search_by_full_name(params[:term]) if params[:term].present?
@books = @books.order(:title)
respond_to ...
end
Eyeslandic
  • 14,553
  • 13
  • 41
  • 54
0

Solved it... I wasn't applying current_user on each book, in views/index... That way, each user had their own books db but when rendering index, it was showing everyone's books, no matter which user created it... It's the simple things, most of the times:P

Funk Dr
  • 31
  • 5