0
votes

first time asking a question on stack overflow :)

I'm having a conflict between friendly_id and active admin (it's an assumption), as discussed in many threads here. I've looked at all those threads, but I'm not entirely sure they solve my problem. Sorry for the really long post!

I'm trying to create friendly links to products on my website. I've added the friendly_id gem and everything works fine in my dev and staging environments, but friendly links fail on production. Here is all my code:

Model:

class Product < ActiveRecord::Base
  extend FriendlyId
  friendly_id :name, use: :slugged
  ...
end

Controller:

class ProductsController < ApplicationController
  before_filter :get_product, only: [:show]
  ...

  private

  def get_product
    @product = Product.friendly.find(params[:id])
  end
end

All my product records have a completed slug field at this point. I don't want to use slugs in my admin interface, so when I came across a solution here, I went ahead and modified it a bit to get active admin to work together with friendly_id.

config/initializers/active_admin.rb:

ActiveAdmin.setup do |config|
  ...

  config.before_filter :revert_friendly_id
end

I've defined revert_friendly_id in the application controller:

class ApplicationController < ActionController::Base
  ...
  protected

  def revert_friendly_id
    model_name = self.class.name.match(/::(.*)Controller$/)[1].singularize

    # Will throw a NameError if the class does not exist
    Module.const_get model_name

    eval(model_name).class_eval do
      def to_param
        id.to_s
      end
    end
    rescue NameError
  end
end

I've noticed that when I first deploy to production via capistrano, the friendly links work as expected. So my product links are accessible with: http://website.com/products/my-product-slug. But the minute I access the admin interface on production, the links immediately switch back to product ids instead: http://website.com/products/12345. I'm not entirely sure how to resolve this problem, though I understand why it might be happening, can someone help me please?

4

4 Answers

2
votes

Here is how I solved the problem. Based on armstrjare's fix at this link.

I removed the revert_friendly_id function from my application controller and the before_filter from my config. Then just added the following to app/admin/product.rb:

ActiveAdmin.register Product do

  around_filter do |controller, action|
    Product.class_eval do
      alias :__active_admin_to_param :to_param
      def to_param() id.to_s end
    end

    begin
      action.call
    ensure
      Product.class_eval do
        alias :to_param :__active_admin_to_param
      end
    end
  end
...
end

And everything worked as expected. Hope this helps someone else!

1
votes

I found a very simple solution: Just overwrite the to_param in your model and check if it is called from active_admin.

app/models/product.rb:

class Product < ActiveRecord::Base
  def to_param
    if caller.to_s.include?"active_admin"
      id && id.to_s
    else
      slug
    end
  end
end
0
votes

When you set the to_param method, it will be set on the entire application. So you have to check if the requested controller is in the Admin namespace or not. Based on that you have to switch back the return of the to_param method.

0
votes

You can redefine find_resource method in controller:

   controller do
      def find_resource
        scoped_collection.friendly.find(params[:id])
      end
   end

For the active_admin belongs_to association you can to use the finder: option (from https://github.com/activeadmin/inherited_resources/blob/master/lib/inherited_resources/belongs_to_helpers.rb#L17)

For example: belongs_to :content, finder: :find_by_slug!