rails friendly_id bad request - ruby-on-rails

I'm new to rails and currently involved in an internship and I was assigned to use the friendly_id gem for my tournament class, this is part of the code in it:
class Tournament < ApplicationRecord
extend FriendlyId
friendly_id :url_id
...
end
I don't use a slug since I have a url_id attribute that stores my desired url and when I try with the old .../tournaments/1 everything's all good but with .../tournaments/example I get "example is not a valid value for id" with code 103, status 400. Any ideas what the problem might be?

You have to update your controller for Tournaments so that it uses friendly.find method instead of the find.
# Change this:
Tournament.find(params[:id])
# to
Tournament.friendly.find(params[:id])

Related

Rails Friendly_ID Multiple model creation with slug on same field failing

I am running a Rails 5 application which has 2 models - a User and a Provider. I am using multiple table inheritance to show that each Provider "is a" User (via the active_record-acts_as gem). So, in effect, creating a Provider with the related fields would create a User at the same time.
I wanted to implement slugging for these models, so I integrated the friendly_id gem for that purpose.
Both models are slugged via a field called username. The code in question being:
class User
extend FriendlyId
friendly_id :username, use: :slugged
# ...
end
for the User model and
class Provider
extend FriendlyId
friendly_id username, use: :slugged
def username
acting_as.username # this fetches the parent model (User)'s username field.
end
# ...
end
for the Provider model.
When I attempt to create a Provider via a controller action (providers#create), it fails, with the error being:
TypeError at /providers
nil is not a symbol nor a string
The stack trace identifies the problem to be at lib/friendly_id/slugged.rb:299, which is the body of the should_generate_new_friendly_id? method. This method was called by the set_slug method in the same file, slugged.rb.
I have created an issue on the GitHub page of friendly_id, where you can find the request parameters and full stack trace.
Edit: added friendly_id_config for both: https://gist.github.com/mindseyeblind/9b78c588f5008a494f7157e72da1de6e

scaling issues using friendly_id

Okay so I'm working on making a friendly_id that allows me to scale it effectively. This is what I got so far. What it does is essentially add +1 on a count if you have a matching name. So if you are the 2nd person to register as John doe your url would be /john-doe-1.
extend FriendlyId
friendly_id :name_and_maybe_count, use: [:slugged, :history]
def name_and_maybe_count
number = User.where(name: name).count
return name if number == 0
return "#{name}-#{number}"
end
However this piece of code is still bringing me some issues.
If I have created a user called John Doe. Then register another user called John Doe the slug will be /john-doe-UUID. If I register a third user then it will receive the slug john-doe-1.
If I have two users. One that registered with the name first. Say Juan Pablo. Then he changes his name to 'Rodrigo', and then change it back to 'Juan Pablo'. His new slug for his original name will be 'juan-pablo-1-UUID'.
I know this is minor nitpick for most of you but it's something that I need to fix!
You want to overwrite to_param, include the id as the first bit of the friendly id
I extend active record like this in one of my apps,
module ActiveRecord
class Base
def self.uses_slug(attrib = :name)
define_method(:to_param) do
"#{self.id}-#{self.send(attrib).parameterize}"
end
end
end
so I can do
uses_slug :name
in any model
but this alone in any model should work:
def to_param
"#{self.id}-#{self.my_attrib.parameterize}"
end
The benefit of this is that in the controller you when you do
Model.find(params[:id])
you don't have to change anything because when rails tries to convert a string like "11-my-cool-friendly-id" it will just take the first numeric bits and leave the rest.

friendly_id and acts_as_paranoid creating duplicate slugs

I'm current using acts_as_paranoid and friendly_id (5.0.1) on a model and when I destroy a model and try to create a new one that will generate the same slug I get:
ERROR: duplicate key value violates unique constraint "index_papers_on_slug"
I need to somehow get the code that checks if a slug already exists check within the scope of all of the objects not just the non-deleted ones.
How can I get friendly_id to use with_deleted when checking if a slug already exists. I should note that I am also using slug history which may be complicating things further.
Upon digging deeper I realized that since I am using history the slug is being fully deleted while the object is just being soft deleted:
DELETE FROM "friendly_id_slugs" WHERE "friendly_id_slugs"."id" = $1 [["id", 9423]]
So, I just need to figure out how to prevent this and I should be okay since it looks like the friendly_id code itself is already using unscoped when trying to find a valid slug.
Adding the following to the model allowed me to overrride the dependent destroy on the slugs
def has_many_dependent_for_slugs; end
The solution comes from a comment on this github issue.
Friendly_id has a module called scoped which allows you to generate unique slugs within a scope. So, probably
class Paper < ActiveRecord::Base
extend FriendlyId
friendly_id :title, :use => :scoped, :scope => :unscoped
end
will resolve the problem.
I just came across this issue too and I figured two different ways to address it.
Solution 1:
Use dependent: false.
friendly_id :title, dependent: false
Solution: 2
Overcoming this problem without overriding the dependent destroy for anyone that wants to avoid that.
The friendly_id gem uses a method called scope_for_slug_generator to set the model scope. That means we could override this method by adding the following to app/config/initializers/friendly_id.rb.
module FriendlyId
def scope_for_slug_generator
scope = if self.class.base_class.include?(Paranoia)
self.class.base_class.unscoped.with_deleted
else
self.class.base_class.unscoped
end
scope = self.class.base_class.unscoped
scope = scope.friendly unless scope.respond_to?(:exists_by_friendly_id?)
primary_key_name = self.class.primary_key
scope.where(self.class.base_class.arel_table[primary_key_name].not_eq(send(primary_key_name)))
end
end

friendly_id and routes.rb - rails

I'm currently using friendly_id gem in rails and noticed that if someone names a post "About" that it overwrites the /about path that I have assigned to a static page in my routes.rb file.
This is my current code:
extend FriendlyId
friendly_id :title, use: :history
If there are prior posts with the same name...it adds a --2. But friendly_id seems to ignore static routes in my routes.rb.
Is there a way to make friendly_id recognize and not overwrite these routes?
Thank you
FriendlyID includes a Reserved module which prevents a list of provided words from being used as friendly slugs. You could add your static routes to the reserved words array which would prevent someone from overwriting your routes.
From the FriendlyId RDocs
FriendlyId.defaults do |config|
config.use :reserved
# Reserve words for English and Spanish URLs
config.reserved_words = %w(new edit nueva nuevo editar)
end
If you still want to allow for a title that is reserved you can make a new method that FriendlyId would use for the slug. This piece from the RDocs explains that
Column or Method?
FriendlyId always uses a method as the basis of the slug text - not a column. It first glance, this may sound confusing, but remember that Active Record provides methods for each column in a model's associated table, and that's what FriendlyId uses.
Here's an example of a class that uses a custom method to generate the slug:
class Person < ActiveRecord::Base
friendly_id :name_and_location
def name_and_location
"#{name} from #{location}"
end
end
bob = Person.create! :name => "Bob Smith", :location => "New York City"
bob.friendly_id #=> "bob-smith-from-new-york-city"
You could create a method like :title_with_id or :title_with_rand. it's up to you and how you'd like the slugs to look.
You would also want to make sure your routes.rb has your static routes listed prior to the routes for with the friendly id. The first route dispatcher matches is where the request will be processed.

how to display path with FriendlyId, rails

My task is to be able to see the path of the current category or product in browsing bar.
At this moment I just can see current category like this
localhost:3000/categories/smalcinataji
but I want like this
localhost:3000/categories/atkritumu-parstrades-tehnika/smalcinataji
To create pretty urls I am using gem called FriendlyId from this example http://railscasts.com/episodes/314-pretty-urls-with-friendlyid?view=asciicast
Thanks!
FriendlyId can take a method to construct the slug.
class Person < ActiveRecord::Base
friendly_id :category_and_subcategory
def category_and_subcategory
"#{my_category_method}/#{my_subcategory_method}"
end
end
Note that there might be an issue with routing due to the additional slash, but there's certainly a fix for this, too, if nescessary.

Resources