1

I am asking almost to the same question asked here: Encrypted ID in URLs

Only I don't necessarily need the ID encrypted, I use a random string code. And I have tried a similar solution to what João Carlos Ottobboni answered then, with FriendlyId, as below:

In my models/coupon.rb

class Coupon < ApplicationRecord
  extend FriendlyId
  friendly_id :code #code is already a coupon column

  validates :code, uniqueness: true
  before_create :generate_code

  def generate_code
    all_letters = [('A'..'Z'), ('0'..'9')].map(&:to_a).flatten
    random_string = (0...6).map { all_letters [rand(36)] }.join
    self.code = random_string
  end

And in my controllers/coupon_controller.rb

class CouponsController < ApplicationController
before_action :set_coupon, only: [:show, :edit, :update, :redeem, :destroy]
...
  private
    def set_coupon
      @coupon = Coupon.friendly.find(params[:id])
    end

When I'm redirected to a specific coupon path it actually works, redirects me to coupons/SJKE3K instead of coupons/13. But it doesn't prevent me from been able to type 13 in the url and it redirects me too. How can i avoid that? I need the coupons to be accessible only through the code and not through the id.

  • either need to change the primary key of the table to the code, or have your controller return a not found when given an integer id – dbugger Jan 13 '22 at 14:58

1 Answers1

1

Coupon.friendly.find(params[:id]) allows both code and id to be used to find the record. If you switch to Coupon.find_by!(code: params[:id]) only the code will be able to find the coupon.

In that case you don't need Friendly ID at all, you can just continue manually generating the code and finding the record with it.

That will require a bit more work when generating forms that use the coupon or routes including the coupon as these will always use the integer ID by default - you'll have to explicitly pass id: coupon.code as an argument to the url/path helpers and pass url: my_path(id: coupon.code) or similar when creating forms.

Matt Rohrer
  • 137
  • 6
  • Thanks! Exactly what i was looking for. I finally kept friendly id, as I already installed it and so I didn’t have to change id to code in every path as you mention. In one custom path from another model, where I passed the id manually: controller_action_path(id: coupon.id) I had to change it to code though: controller_action_path(id: coupon.code) – Jose Agustin ESPILDORA VIAL Jan 14 '22 at 10:27