3

I want to limit the amount of records a user can add to the database.

I'm not sure of the 'Rails' way to go about this...

I am using Devise and thought of creating a custom validation method but you can't access current_user from within a model and it isn't correct.

How can I do this from the controller and still return an error message to my users?

I had this

 validate :post_count

  def post_count
    current = current_user.posts.count
    limit = current_user.roles.first.posts.count

    if current > limit
      errors.add(:post, "Post limit reached!")
    end
  end

but it isn't the correct way to go about it as it would be hacky to get the current_user into the model

Max Rose-Collins
  • 1,904
  • 5
  • 26
  • 45
  • Perhaps you could validate on creation of a new post. Then you could count how many posts were created by the same user as is the creator of the post currently being created (thus dodging the question of current_user) and compare that to the limit for that user. – Coenwulf Mar 25 '14 at 15:59
  • Okay how can I check 'limit = current_user.roles.first.posts.count' from within the model though? – Max Rose-Collins Mar 25 '14 at 16:03
  • 1
    See backpackerhh's answer, but I'd recommend moving the code to retrieve the limit to a method on the User class. – Coenwulf Mar 25 '14 at 16:17

1 Answers1

3

You could do something like this:

class User < ActiveRecord::Base
  has_many :domains
  has_many :posts, through: :domains

  def post_limit
    roles.first.posts.count
  end
end

class Domain < ActiveRecord::Base
  belongs_to :user
  has_many :posts
end

class Post < ActiveRecord::Base
  belongs_to :domain
  delegate :user, to: :domain
  validate :posts_count_within_limit, on: :create

  def posts_count_within_limit
    if self.user.posts(:reload).count >= self.user.post_limit # self is optional
      errors.add(:base, 'Exceeded posts limit')
    end
  end
end

Based on this answer.

Community
  • 1
  • 1
backpackerhh
  • 2,333
  • 1
  • 18
  • 21
  • Okay that looks good but I need to get the current users limit from the db? – Max Rose-Collins Mar 25 '14 at 16:02
  • Just replace `` with `user.roles.first.posts.count` (assuming that's the limit in the DB). – Chowlett Mar 25 '14 at 16:05
  • 2
    I'd recommend moving the retrieval of the limit to a method on the user object rather than inline in the validation. (i.e., replace self.user.roles.first.posts.count with self.user.post_limit in the validation and put that code in the post_limit method on the User class. – Coenwulf Mar 25 '14 at 16:16
  • okay this is just what I want except I realised it wont work because I have another model between user and post... It goes `user has_many :domains, domain has_many :posts`. I tried `delegate :user, :to => :posts` in the domain model but it doesn't seem to work? I'm getting the error `undefined method `user'` – Max Rose-Collins Mar 25 '14 at 16:19
  • @Max Rose-Collins You can try with a `has_many through` relationship. I have updated my answer again. – backpackerhh Mar 25 '14 at 16:21
  • Well, the `belongs_to :user` is no longer valid, because you don't have a `user_id` on `posts` table. Maybe delegating `user` to `domain` does the trick. – backpackerhh Mar 25 '14 at 16:23
  • 1
    @MaxRose-Collins Perfect! :) – backpackerhh Mar 25 '14 at 16:27
  • @backpackerhh A quick question, I see you have used :base for errors. These don't show up on my app, any idea why? – Max Rose-Collins Mar 25 '14 at 18:20
  • A base error is an error that is not tied to any specific field but rather to the record as a whole, so you need to display this errors with `.errors.full_messages`. If you're using `simple_form` you can do it with `= f.full_error :base`. – backpackerhh Mar 25 '14 at 19:15