I ignorantly named a model in my Rails app System, which is also a ruby core method. This model is in a relationship with another model Project, which I am trying to index.
Ideally, I am looking to setup my index like this:
define_index do
indexes :name, :sortable => true
indexes system(:name), :sortable => true, :as => :system_name
end
I could change the model name, but I'd call that a compromise, and I'm not convinced I need to. Is there a good work-around for this?
ruby 1.8.7, rails 3.0.7, thinking_sphinx 2.0.3
The good work around for naming variables or user-level Classes with reserved words (language keywords and platform-level methods/classes) is not do it in the first place.
The second best workaround is to use scoping :: to make sure the name you are calling is the one you want
::system() # calls the actual system method as defined by Ruby
APPNAME::MODEL_NAME # would call the model defined as `APPNAME::MODEL_NAME`
I can't really think of a workaround without namespacing your models (although knowing Ruby, its more than possible some functionality exists-- just never needed it myself). Prolly all of them tbh since it would get even more confusing if only half your models were namespaced. In the long run, its just more typing remembering to namespace everything.
Related
I have a Rails model, which is using the str_enum gem.
I'm building a generator which reads the models and creates pages for them, and so I'd like to be able to understand what str_enums are attached to a model.
For example
class User < ApplicationRecord
str_enum :email_frequency, %i[every daily weekly], default: 'every'
end
Ideally, I'd like to be able to query the User model and understand there is a str_enum attached to email_frequency, with values of every, daily & weekly.
Once I can understand there is a str_enum attached to a given field, I can pluralize the field and get the values:
irb(main):004:0> User.email_frequencies
=> ["every", "daily", "weekly"]
The question has also be asked over here and the suggestion is to use Module#prepend. I'm familiar with prepend to conditionally insert methods into a model.
How can I use it for this problem?
EDIT
This is quite simple with validations, for example: get validations from model
If I understand your question correctly is that you wanna get all column that has attached with enum string. If so you can override the gem method like this
# lib/extenstions/str_enum.rb
module Extensions
module StrEnum
module ClassMethods
def str_enum(column, *args)
self.str_enums << column.to_s.pluralize
super
end
end
def self.prepended(base)
class << base
mattr_accessor :str_enums
self.str_enums = []
prepend ClassMethods
end
end
end
end
In the User model
prepend Extensions::StrEnum
Now you can use
User.str_enums
to list all columns has attached with str enum.
Make sure you have add lib directory into load path.
So for starters, you could, of course, use the approach that Ninh Le has described and monkeypatch your desired behavior into the gem. In fact, I'm fairly confident that it would work, since your use case is currently relatively easy and you really just need to keep track of all the times the str_enum method gets called.
I would, however, encourage you to consider doing one of two things:
If you plan to do more complex stuff with your enums, consider using one of the more heavy-duty enum gems like enumerize, enumerate_it or active_enum. All of these are packages that have been around for a decade (give or take) and still receive support and all of them have been built with a certain degree of extensibility and introspection in mind (albeit with different approaches).
Have a look at the gem and consider building your own little macro on top of it. IMO one of multiple of Andrew Kane's libraries' biggest weaknesses is arguably their kind of hacky/scripty approach which, while making the libraries hard to extend, makes them inherently easy to understand and thus use as a basis for your own stuff (whereas the gems with a better/more elaborate approach are harder to understand and adapt beyond the means the author has intended to).
Either way, you'll be fine with both of my suggestions as well as Ninh Le's.
I have a Project model and a Developer model. I have the concept of calculating the "interestingness" for a project for a particular developer:
class Project < ActiveRecord::Base
def interestingness_for(developer)
some_integer_based_on_some_calculations
end
end
I think it would be neat, instead of having something like Project.order_by_interestingness_for(bill), to be able to say
Project.order(:interestingness, :developer => bill)
and have it be a scope as opposed to just a function, so I can do stuff like
Project.order(:interestingness, :developer => bill).limit(10)
I don't know how to do this, though, because it's not obvious to me how to override a scope. Any advice?
Assuming you will not need to use the standard ActiveRecord order query method for the Project class, you can override it like any other class method:
def self.order(type, options)
self.send(:"special_#{type}_calculation_via_scopes", options)
end
Then the trick is to ensure you create the needed calculation methods (which will vary according to your interestingness and other algorithms). And that the calculation methods only use scopes or other AR query interface methods. If you aren't comfortable converting the method logic to a SQL equivalent using the query interface, you can try using the Squeel DSL gem which can potentially work with the method directly depending on your specific calculation.
If you may be needing the classic order method (and this is usually a safe assumption), then don't override it. Either create a proxy non-ActiveRecord object for this purpose, or use a different naming convention.
If you really want to, you can use aliasing to achieve a similar effect, but it may have unintended consequences for the long term if the second argument ('options' in this case) suddenly takes on another meaning as Rails progresses. Here is an example of what you can use:
def self.order_with_options(type, options = nil)
if options.nil?
order_without_options(type)
else
self.send(:"special_#{type}_calculation_via_scopes", options)
end
end
class << self
alias_method_chain :order, :options
end
I'm using DataMapper in a Rails project, and have found that calling to_json on either a model instance or collection results in weird behavior: either a circular reference error from JSON, or an infinite series of the same query.
Assuming this was a problem with my model definitions, I opened a Rails console and created the simplest possible model:
class Foo
include DataMapper::Resource
property :id, Serial
property :name, String
end
Foo.auto_migrate! # create db table `foos` for this model
After saving an instance of this model, I did this:
f = Foo.first
f.to_json
At this point, the process appears to hang. If I tail -f log/development.log, I see this query executing over and over:
SQL (0.084ms) SELECT `id`, `name` FROM `foos` ORDER BY `id`
Ruby's memory usage continues to grow until I interrupt the command or kill the Ruby process. This is the same problem I had with my actual models, so I don't think it was related to a wrong model definition.
What causes this bizarre behavior?
It seems that the Object#to_json method, as implemented by ActiveSupport, serializes all the attributes of the object. Datamapper maintains a self-referential variable (#_repository) that sends the method into a recursive tailspin.
Good news is that the dm-serializer gem (as you mentioned) provides the necessary functionality, and the Rails has already stated how to fix the problem in the dm-rails project (it just hasn't happened yet).
For normal columns, you can get at them via the columns class method. However, associations may be named something quite different if the foreign_key option is set in the relationship method. For example, given
class Post
has_many :comments, :foreign_key => :message_id # this is a contrived example
end
if I did Post.column_names I could get at message_id, but is there any way to get comments?
Model.reflections gives information about a model's associations. It is a Hash keyed on the association name. e.g.
Post.reflections.keys # => ["comments"]
Here is an example of some of the information it can be used to access:
Post.reflections["comments"].table_name # => "comments"
Post.reflections["comments"].macro # => :has_many
Post.reflections["comments"].foreign_key # => "message_id"
Note: this answer has been updated to cover Rails 4.2 based on MCB's answer and the comments below. In earlier versions of Rails the reflection's foreign_key was accessed using primary_key_name instead, and the keys for the reflections may be symbols instead of strings depending on how the association was defined e.g. :comments instead of "comments".
For future Googlers in Rails 4 the answer would now be:
Post.reflections[:comments].foreign_key # => "message_id"
Taken from here: https://stackoverflow.com/a/15364743/2167965
EDIT:
reflections, as of 4.2, now takes strings instead of symbols which is a fun bug to track down. If you want to keep using symbols you should switch to reflect_on_association(:assoc_name). Also note reflections are actually the public api which will keep reporting things like HABTM, even though it's all has many through under the hood. The reflections Rails is actually using are now in _reflections
For an ActiveRecord object I use:
object._reflections
So, I can manipulate the Hash returned. For instance:
object._reflections.keys.each do |key|
object.public_send(key).destroy_all
end
The above example delete all the relationships from database.
I'm having a hard time imagining a practical use for Procs and Lambdas in a web app. Does anyone have an example of a situation in your code where they come in handy?
Why in webapps in particular? Do you mean the Ruby on Rails framework, perhaps?
Procs and lambdas are useful when you want to store pieces of code anonymously. Procs and lambdas are very similar to methods, except that they don't have a name. A good example to illustrate this, in ActiveRecord/Rails:
// methods are named
validates_presence_of :foo, :if => :active?
// procs aren't
validates_presence_of :foo, :if => proc {|r| do_stuff }
I general, procs are used for callbacks and hooks, so that you don't have to write named methods and refer to them, putting the code in question directly in the option hashes and such.
You might find this article useful.
I use them on named scopes:
named_scope :last, lambda { |quantity| {:order => "created_at DESC", :limit=> quantity } }
To create an easy way to get the last NUMBER posts, comments, etc.
Now, I kinda cheated there, it's most of a framework thing than a "web app", but I can't think web app are that different from other desktop ones. Both Procs and Lambdas allows you to "save" code for later use, and can help to use behaviour, use more "domain oriented" methods and cleaning up some more "regular code"
Obviously, procs and lambdas are a necessary component of anything related to callbacks, but in most cases in ruby this can be accomplished with a block.
One place where procs or lambdas are useful that isn't related to callbacks is things like compiling a regular expression. Of course, regex are part of the language, so you don't need procs for this, but you may find yourself writing some other kind of procedure that has a one-time cost that can be reused, but isn't really worth creating a full blown class.
In my case, I had an object (publist) which contained a list of strings. In one area of the code, I needed to repeatedly check whether some other set had any members in that list. It would have been inconvenient and have poor performance to change the data type so that the object contained a set. So what I did was create a method that returned a matcher lambda that had a local set representation of this list.
I could have returned a set, but the business logic of whether an item matched logically belonged to the publist. I could in the future change this to support substrings or regular expressions and users of the matcher would still have the same api.
Using lambda or proc is a matter of programming style called functional programming. There are several interfaces in Rails where you might like to pass a block object(lambda or procc), just like validations:
class Person < ActiveRecord::Base
validates_acceptance_of :terms_of_service :if => Proc.new { |user| user.signup_step > 2 }
end
You can design some interfaces like that, where you can give the user the choice of either passing a method name(symbol) or a proc(or lambda) object to specify some logic.
Another place in Rails for example is where you can set layouts dynamically:
class WeblogController < ActionController::Base
layout proc{ |controller| current_user.logged_in? ? "writer_layout" : "reader_layout" }
end