I am using FriendlyId across a bunch of different model. For a particular use-case with usernames, I can't use FriendlyId but still want to make sure the username is not being used as a slug in any of those models.
Currently, I have a .exists query for each model using FriendlyId. It doesn't feel super efficient, so I am wondering if there is a more efficient way of doing this by just querying the slugs column in friendly_id_slugs table that the library creates?
I'm on Rails 5.1, Postgres 9.5.x and FriendlyId 5.2.3
The answer by #Ben helped me find the ideal solution. It turns out that FriendlyId has an internal model - FriendlyId::Slug, that is backed by the friendly_id_slugs table.
So, a query like the following worked for me:
FriendlyId::Slug.where(
sluggable_type: ["Animals", "Plants"]
)
.where('lower(slug) = ?', potential_username.downcase)
.exists?
Defining a model map it to its table, simply create a app/models/friendly_id_slug.rb file, containing :
class FriendlyIdSlug < ApplicationRecord
end
You then get a standard model active record querying methods (FriendlyIdSlug.where…)
Alertnatively, running raw sql would apply :
ActiveRecord::Base.connection.execute("select * from friendly_id_slugs etc…")
That is, your .exists? sounds fair too. If you repeat code for each model, you could make a app/models/concerns or app/lib class file you'd reuse in the concerned models
Related
Is there a way in Rails to manipulate database fields and corresponding accessor methods without the „nifty generators” ?
I want users, insofar they are privileged, to be able to manipulate the database structure, that is, at least, to add or delete columns. The privileged user should have the possibility to „Add new” some columns.
Say I have an Object/Table artist and it should “dynamically” receive columns as "date of birth", "has played with", "copies sold"
Not sure if it's a dup. It takes a preliminary decision whether Rails discourages from letting the user do this to begin with or or not. (if that's the case => certainly some noSQL solution)
In pure ruby at least it is easy to dynamically add an attribute to an existing Model/Class like this
Test.class_eval do; attr_accessor "new_attribute"; end
and
Test.new.new_attribute = 2
would return => 2 as expected
In order to create or manipulate a customized input mask / model: can I not manually go the same way the generators go and manually call ActiveRecord::Migration methods like add_column as well as create getter/setter-methods for ORM ?
If yes or no, in both cases, which are they to begin with?
Thanks!
I am not aware of any elegant way to allow an Object to dynamically create new columns. This would not be a good application design and would lead massive inefficiency in your database.
You can achieve a similar type of functionality you seek using ActiveRecord associations in Rails. Here's a simple example for your Artist model using a related Attributes table.
class Artist < ActiveRecord::Base
has_many :attributes
end
class Attribute < ActiveRecord::Base
belongs_to :artist
end
With this association, you can allow your Artist class to create/edit/destroy Attributes. ActiveRecord will use foreign keys in the database to keep track of the relationship between the two models.
If that doesn't work for you, your next best option is to look into NoSQL databases, such as MongoDB, which allow for much more flexibility in the schema. With NoSQL, you can facilitate the insertion of data without a predefined schema.
I'm using Mongoid to build a Rails 4 app.
The problem I'm having right now is how to filter some Mongoid objects through their own relations and have a Mongoid::Criteria at the end instead of an Array.
This is some example code:
class Editor
include Mongoid::Document
has_many :books
def likes
books.collect { |book| book.likes }
end
end
class Book
include Mongoid::Document
belongs_to :editor
end
What I would like to be able to do is something like:
Editor.last.likes.where(:created_at.gt => 10.days.ago)
but of course this doesn't work as Editor.last.likes returns an Array, not a Mongoid::Criteria
I know Mongoid has an aggregation framework but it's not entirely clear to me how to use it, nor if it's the best way to solve my problem.
Suggestions?
TIA,
ngw
The biggest problem you have here is that MongoDB does not do joins like a relational database does. All of the work you are getting for convenience when traversing object properties is being done client side while pulling in the 'related' documents over the wire in a query. But in sending a query, the two collections cannot be joined.
Your workaround solution is to work with the data you can get at in separate queries in order to target the results. One approach is here: rails mongoid criteria find by association
There should be other examples on Stack Overflow. You're not the first to ask.
What is the deal with this? I'm working with a pre-existing that I did not do myself. Everything in the database is labeled in singular form. user, security, spec, etc. I guess the right way would be users, securities, specs. At least that's what ruby on rails try's to lookup when I generate a scaffold .
How do I specifically state to use user instead of users in the sql. I don't see anywhere in my project where it is looking up the sql. I mean if my model is user you would think it would try to lookup user. Instead of users.
Thanks for any help.
You need set_table_name :name_of_the_table in your model (source).
So:
class User < ActiveRecord::Base
set_table_name :user
end
The reason they use plural for the table and singular for the model is because an instance of the model represents one user, whereas the table contains all the users. It's just to make it more readable and logical.
You can specifiy the table name:
How do I explicitly specify a Model's table-name mapping in Rails?
I think the problem is trivial. I have two models: User and Betting.
User
has_many :bettings
Betting
belongs_to :user
I just want to get the users ordered by who made more bettings.
Are you on Rails2 or Rails3?
On Rails3, you can use the Ruby sort method and something like:
User.includes(:bettings).sort{|x,y| x.bettings.size <=> y.bettings.size}
Of course, in this case the sorting occurs after the SQL request, which is not optimum if you have large tables… I'm trying to figure how to do it at the SQL level with no answer yet…
I have an existing database(Postgresql). How can i create models from it? How can i pass column names for Rails? As if something like this:
Person:
Name :table_name_for_name_attribute
Surname :table_name_for_surname_attribute
PersonalCode :table_name_for_perconal_code_attribute
Unfortunately, my database is not following Rails convention, because not all tables are named in English. Any ideas how can i map it?
UPDATE reverse_scaffold script generates only model, but i need controller and view forms also.
You can define a table name not matching the model's using the table_name method.
class MyModel < ActiveRecord::Base
def self.table_name
'my_table_name'
end
end
Change the value of 'my_table_name' to your effective table name.
For generating controllers and views with automatic methods to create, update, delete and view database objects, you should create a scaffold. There's some pretty good documentation on the rails guides about that.
In your model, you'll need to tell ActiveRecord what the table name and primary key field column is named if they don't follow the conventions.
class MyLegacyTable < ActiveRecord::Base
self.table_name = "some_name"
self.primary_key = "some_name_primary_key_field"
end
Once you've done that, ActiveRecord knows the some_name_primary_key_field as id, which makes life much easier.
Rails doesn't need to know the column names it figures them out when it connects to the database.
As others have said you can specify a table name in the model.
As for generating controllers/views, you're pretty much own your own. script/generate scaffold is deprecated. It still works as far as creating things, but you need to pass all column names and times on the command line.
Instead have a look at the ActiveScaffold Plugin, it has a similar end result. But is much more robust and easier to adapt to model changes.