rails reference model from variable name - ruby-on-rails

i have some code that uses a string to determine dynamically what model class to use and for what field to find_by() on. however, i'm having a hard time with how to use these variables to get the model instance. specifically, i have
class Item
include MongoMapper::Document
key :my_variable, String
in my code i have
m = "Item"
f = "my_variable"
and i want to be able to
i = m.find_by_my_variable( f )
result = i[f]
any help is appreciated!

Since you're in Rails (judging by the category tag) you can use:
m = m.constantize
to make the string a constant, and then would something like this work for your query?
m.where("#{f} = ?", some_value)
(EDIT) or use send as ismaelga suggested, if you don't want an ActiveRecord::Relation array object

You could do eval(m.capitalize).send("find_by_#{variable_name}", variable_content)
Capitalize it's only to be sure it gets a capital letter.

Related

How do you create and use functions in Arel that are not bound to a column?

Lets say I want to create:
SELECT * FROM memberships WHERE memberships.expires < NOW()
I attempted:
fn = Arel::Nodes::Function.new("NOW")
memberships = Arel::Table.new("memberships")
memberships.project(Arel.star).where(
memberships[:expires].lt(fn)
)
Which give TypeError (Cannot visit Arel::Nodes::Function).
All the sources I have found when just cover using Arel::Nodes::NamedFunction to create functions that are bound to a specific attribute. I do know there are other ways to solve this like sql literals but I'm curious as to how to actually use Arel::Nodes::Function.
You can use Arel::Nodes::NamedFunction.
This class initializes with the name of the function and an arguments array. The Vistor for a NamedFunction will assemble the SQL as FUNCTION_NAME(comma, separated, arguments).
Since NOW has no arguments all we need to do is pass an empty arguments array.
fn = Arel::Nodes::NamedFunction.new("NOW",[])
memberships = Arel::Table.new("memberships")
memberships.project(Arel.star).where(
memberships[:expires].lt(fn)
).to_sql
#=> "SELECT * FROM [memberships] WHERE [memberships].[expires] < NOW()"
Function appears to be a super class for inheritance purposes only, children include Sum,Exists,Min,Max,Avg, and NamedFunction (which allows you to call any other function by name as shown above)

Using Variables for Model Names in Active Record

I am writing a seed file that will make several API calls via HTTParty in order to populate the database. I am pulling the same information for several different models and I would like to be able to use a single method for all of them. However, I cannot figure out how to reference the model name through a variable. Specifically I am having difficulties because each of these must belong to another model. I have tried the following:
def create_assets(subject, model, geokit_hoods)
response = HTTParty.get("https://raw.githubusercontent.com/benbalter/dc-maps/master/maps/#{subject}.geojson")
parsed = JSON.parse(response)
collection = parsed["features"]
collection.each do |station|
coordinates = station["geometry"]["coordinates"].reverse
point = Geokit::LatLng.new(coordinates[0], coordinates[1])
geokit_hoods.each do |hood|
if hood[1].contains?(point)
hood[0][model].create(coordinates: coordinates, name: station["properties"]["NAME"], address: station["properties"]["ADDRESS"])
break
end
end
end
end
Which I called via the following:
create_assets("metro-stations-district", "metros", geokit_hoods)
hood[0] refers to an existing neighborhood model, and hood[1] is the polygon associated with that neighborhood. The code works when referring to hood[0].metros.create(...), but I am looking for a way to make this method useful across many models.
Any ideas would be appreciated!
For now I'm going to assume that what you have in the variable is a String that is the name of the class in table-name format. eg in your example you have metros in the variable... from that I assume you have a Metro class which you are trying to create.
If so... you first need to convert your lowercase table-name style variable ("metros") into a class name-style eg "Metro"
Note: this is title cased and singular (rather than plural).
Rails has a method to do this to strings for exactly the purpose you want: classify eg you could use it thus:
model_name = hood[0][model] # 'metros'
model_name.classify # 'Metro'
Note that it's still just a string, and you can't call create on a string.. so how do you make it the real class? constantize
Use this to turn the string into the actual model-class you're trying to find... which you can then call create on eg:
model_name = hood[0][model] # 'metros'
the_klass = model_name.classify.constantize # Metro
your_instance = the_klass.create(...)

MVC Database to list with id reference

I'm writing an MVC application and want to query my database with a search parameter and put all of the results into a list. Right now my code to try this looks like:
Character character = db.Characters.ToList().Find(User.Identity.GetUserId());
Which is throwing up a error. Is there a way I can do this? Break it down into two statements for example? I tried
Character character = db.Characters.Find(User.Identity.GetUserId());
character = character.ToList();
but that isn't working either.
When using the extension method Find() you must be sure that in your model you have the attribute [Key] in the property representing your Id (primary key in your table).
And you can try like this:
Character character = db.Characters.Find(User.Identity.GetUserId());
The line above will work but not this one character= character.ToList(); because you declare character as an object and you can't assign it to a list of object in your case Character
If you want it to work, you can do something like this:
var myCharacters =db.Characters.Where(c=>c.someField=="someValue");
List<Character> myList = myCharacters.ToList();
Hope it will help.

Active record where query for value inside of an array

Question: Is it possible to build a class method scope that can query objects based on values inside an array in a table? If yes, how can I do this?
In my example, I have a “wells” table that has an array field called “well_tags”. I want to build a query that returns all objects that have a specified value (such as “ceramic”) in the wells_tags array. The basic query would be something like this:
#well = Well.all
#query = #well.where(“well_tags contains ceramic”)
And then the class method scope would look something like this, with the “well_tag_search” param passed in from the controller:
class Well < ActiveRecord::Base
def self.well_tag_filter(well_tag_search)
if well_tag_search.present?
where(“well_tags contains ceramic")
else
Well.all
end
end
I found another post that asks a similar question (see link below), but I cannot get the answer to work for me...the result is always 'nil' when I know there should be at least 1 object. I am a beginner using sqlite (for now) as my database and rails 4.0.
Active Record Query where value in array field
Thanks!
UPDATE: some progress
I figured out how to create an array of all the objects I want using the ‘select’ method. But I still need to return the results as an Active Record object so I create a class method scope.
#well = Well.select
{ |well| if well.well_tags.present?
then well.well_tags.include? ‘ceramic' end }
#well.class #=> array
Not sure where Show is coming from.
Can you try doing Well.all instead of Show.all?

<< operator in ruby

I am quite new to ruby,
I came across the following code in rails, but I don't know how the "<<" operator works and what it does in the below code
def <<( rate )
r = Rating.new
r.rate = rate
r.rateable = proxy_owner
...
...
end
class << ActiveRecord::Base
...
...
end
Can anybody explain to me?
Edit: here is the code https://github.com/azabaj/acts_as_rateable/blob/master/lib/acts_as_rateable.rb
def <<( rating ):
In your example, this is used to add a rating to a rateable model. (E.g. in acts_as_rateable.rb:41), similar to appending something to a string (str << "abc"). As it is within a module, it will only be included for the models that you declare as rateable.
class << ClassName:
All the methods inside of this block will be static / class methods (see this blog entry). (In this case, all the models will have the methods Model.example_static_method.)
Nearly all operators in Ruby are actually instance methods called on the object preceding them.
There are many different uses for << depending on the object type you're calling it on. For example, in an array this works to push the given value onto the end of the array.
It looks like this is for a Rails model object, so in that case I would say that this is an auxiliary method called when you append a model object to model object collection. For example, in this case you might be appending a Rating to a Product.
If you showed the whole method definition and showed what class it's in, I could provide a more specific answer.

Resources