1

i'am playing with pundit gem. i need to show post's title in a flash message

#config/locales/pundit.en.yml

en:
  pundit:
    default: 'You cannot perform this action.'
    post_policy:
      share?: 'You cannot share post %{post.title}!'

controller:

#posts_controller.rb

def share
  @post = Post.find(params[:id])
  authorize @post
  @post.share
  redirect_to @post
end

all i receive is the exact the same string without any errors and substitutions

You cannot share post %{post.title}!

any suggestions? thanks

okliv
  • 3,909
  • 30
  • 47

2 Answers2

2

The I18n module has no way of knowing that post.title refers to @post.title. Rails does some of that kind of magic with its form helpers, but that magic does not extend to Pundit.

Here's how the Pundit docs suggest customizing your error messages:

Creating custom error messages

NotAuthorizedErrors provide information on what query (e.g. :create?), what record (e.g. an instance of Post), and what policy (e.g. an instance of PostPolicy) caused the error to be raised.

One way to use these query, record, and policy properties is to connect them with I18n to generate error messages. Here's how you might go about doing that.

class ApplicationController < ActionController::Base
  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

  private

  def user_not_authorized(exception)
    policy_name = exception.policy.class.to_s.underscore

    flash[:error] = t "#{policy_name}.#{exception.query}", scope: "pundit", default: :default
    redirect_to(request.referrer || root_path)
  end
end
en:
 pundit:
   default: 'You cannot perform this action.'
   post_policy:
     update?: 'You cannot edit this post!'
     create?: 'You cannot create posts!'

Of course, this is just an example. Pundit is agnostic as to how you implement your error messaging.

From that information we could extrapolate something like the following:

private
def user_not_authorized(exception)
  policy_name = exception.policy.class.to_s.underscore
  interpolations = exception.query == 'share?' ? { title: @post.title } : {}

  flash[:error] = t "#{policy_name}.#{exception.query}", scope: "pundit", default: :default, **interpolations
  redirect_to(request.referrer || root_path)
end

And then, in your locales:

en:
  pundit:
    default: You cannot perform this action.
    post_policy:
      share?: You cannot share post %{title}!

I don't have an app with Pundit in front of me so I can't test this; it's likely you'll need to finesse it a bit.

okliv
  • 3,909
  • 30
  • 47
Jordan Running
  • 102,619
  • 17
  • 182
  • 182
-1

The problem is that single(') quotes don't allow string interpolation only double(") quotes

Taken from Programming Ruby

Double-quoted strings(...) can substitute the value of any Ruby expression into a string using the sequence #{ expr }. If the expression is just a global variable, a class variable, or an instance variable, you can omit the braces.

R. Sierra
  • 1,076
  • 6
  • 19
  • 1
    The code shown is YAML, not Ruby. You've misunderstood how the I18n module does interpolation—it uses [`sprintf`-style placeholders](https://repl.it/GUhj/1). – Jordan Running Mar 14 '17 at 14:59