Rails: Generating several model migrations with one command? - ruby-on-rails-3

Is it possible to make Rails generate several model migrations in just 1 command? Something like...
$ rails g model Product1 name:string, Product2 name:string, Product3 name:string [...]
Background:
I have to generate about 4'000 models/db tables.
Running 1 generator command for each one would take probably over 10 hours...
Or do I have to think outside the box for a faster solution to this?

Why not just do it in a ruby script?
4000.times do |i|
system("rails g model Product#{i} name:string")
end
I'm sure your models are probably more complicated than a name string for each, but I could easily see you reading them in from a file and parsing the appropriate columns.
Hope it helps.

The solution to the original problem is to use the gem "spring" (it speeds things up a lot):
https://github.com/jonleighton/spring

Related

Trying to refactor Rails 4.2 scope

I have updated this question
I have the following SQL scope in a RAILS 4 app, it works, but has a couple of issues.
1) Its really RAW SQL and not the rails way
2) The string interpolation opens up risks with SQL injection
here is what I have:
scope :not_complete -> (user_id) { joins("WHERE id NOT IN
(SELECT modyule_id FROM completions WHERE user_id = #{user_id})")}
The relationship is many to many, using a join table called completions for matching id(s) on relationships between users and modyules.
any help with making this Rails(y) and how to set this up to take the arg of user_id with out the risk, so I can call it like:
Modyule.not_complete("1")
Thanks!
You should have added few info about the models and their assocciation, anyways here's my trial, might have some errors because I don't know if the assocciation is one to many or many to many.
scope :not_complete, lambda do |user_id|
joins(:completion).where.not( # or :completions ?
id: Completion.where(user_id: user_id).pluck(modyule_id)
)
end
PS: I turned it into multi line just for readability, you can change it back to a oneline if you like.

Rails 3 - Select objects which do not include associated model?

(Using Rails 3)
I have 2 models (Vehicle and Capabilities) in a has_many through association.
So Vehicle 1 can have Capability 1 (eg towing), Capability 2 (eg passenger), Capability 3 (eg flying), etc.
v = Vehicle.first
v.capabilities.pluck(:name) #=> will give something like ['towing', 'passenger', 'flying']
I want to find all vehicles which must not have a particular capability, eg all vehicles which cannot fly.
I have tried queries similar to this below but it still includes flying vehicles, I think mainly because the airplane also has other capabilities.
non_flying = Vehicle.includes(:capabilities).where('capabilities.id NOT IN (?)', [2,3])
non_flying.first.capabilities.pluck(:name) #=> will give something like ['towing'].
Note that the flying capability is not included, but I just do not want this vehicle returned at all. How would I write this?
If possible, I would rather not use meta_wheel or squeel gems, but any arel_table implementation is welcome unless there is a simpler solution.
Try this query
non_flying = Vehicle.all - Vehicle.includes(:capabilities).where('capabilities.id IN (?)', [2,3]).all
I ended up doing something similar to this, inspired by Thaha kp's answer.
# Get all flying vehicles first
subquery = Vehicle.joins(:capabilities).where("capabilities.id IN (?)", 3).pluck("vehicles.id")
# Then get all vehicles not in this flying vehicles array
non_flying = Vehicle.where('vehicles.id NOT IN (?)', subquery).all

Arel: Left outer join using symbols

I have this use case where I get the symbolized deep associations from a certain model, and I have to perform certain queries that involve using outer joins. How can one do it WITHOUT resorting to write the full SQL by hand?
Answers I don't want:
- using includes (doesn't solve deep associations very well ( .includes(:cars => [:windows, :engine => [:ignition]..... works unexpectedly ) and I don't want its side-effects)
- writing the SQL myself (sorry, it's 2013, cross-db support, etc etc..., and the objects I fetch are read_only, more side-effects)
I'd like to have an Arel solution. I know that using the arel_table's from the models I can construct SQL expressions, there's also a DSL for the joins, but somehow i cannot use it in the joins method from the model:
car = Car.arel_table
engine = Engine.arel_table
eng_exp = car.join(engine).on(car[:engine_id].eq(engine[:id]))
eng_exp.to_sql #=> GOOD! very nice!
Car.joins(eng_exp) #=> Breaks!!
Why this doesn't work is beyond me. I don't know exactly what is missing. But it's the closest thing to a solution I have now. If somebody could help me completing my example or provide me with a nice work-around or tell me when will Rails include such an obviously necessary feature will have my everlasting gratitude.
This is an old question, but for the benefit of anyone finding it through search engines:
If you want something you can pass into .joins, you can either use .create_join and .create_on:
join_on = car.create_on(car[:engine_id].eq(engine[:id]))
eng_join = car.create_join(engine, join_on, Arel::Nodes::OuterJoin)
Car.joins(eng_join)
OR
use the .join_sources from your constructed join object:
eng_exp = car.join(engine, Arel::Nodes::OuterJoin).on(car[:engine_id].eq(engine[:id]))
Car.joins(eng_exp.join_sources)
I found a blog post that purports to address this problem: http://blog.donwilson.net/2011/11/constructing-a-less-than-simple-query-with-rails-and-arel/
Based on this (and my own testing), the following should work for your situation:
car = Car.arel_table
engine = Engine.arel_table
sql = car.project(car[Arel.star])
.join(engine, Arel::Nodes::OuterJoin).on(car[:engine_id].eq(engine[:id]))
Car.find_by_sql(sql)
If you don't mind adding a dependency and skipping AREL altogether, you could use Ernie Miller's excellent Squeel gem. It would be something like
Car.joins{engine.outer}.where(...)
This would require that the Car model be associated with Engine like so:
belongs_to :engine

How do I pick the last and the second to last entries in a blog model?

I have a model, blog_posts which has a field "published_at". I'd like to select the latest two blogs from that model to display on my homepage. Not sure how to structure that though.
At the moment I have a work around that takes a slice of the data but it keeps failing when I have nothing in the table, rather than fix this I feel there is probably a better way to retrieve the data.
I need to select the blogs in separate calls, for example
#blog_post.latestpost, #blog_post.secondlatestpost
Is this what you're looking for? :
class BlogPost < Activerecord::Base
def self.latestpost
order("published_at DESC").limit(1).first
end
def self.secondlatestpost
order("published_at DESC").offset(1).limit(1).first
end
end
Use it like this :
BlogPost.secondlatestpost
or
BlogPost.latestpost
Hope this helps.
You could also do:
BlogPost.order(:published_at).last # for the last post
BlogPost.order(:published_at).offset(1).last # for the second to last post
As of Rails 5 you can use BlogPost.second_to_last.
http://api.rubyonrails.org/v5.0/classes/ActiveRecord/FinderMethods.html#method-i-second_to_last
At least since Rails 4.x you can specify how many last records you want. E.g. to fetch last 2 records:
BlogPost.last(2) # BlogPost.last(2).first will return the second last post
The same goes for first(). There are also methods second(), third(), fourth(), fifth(), forty_two(). And starting with Rails 5.x, second_to_last(), third_to_last().
You could also use ActiveRecord
BlogPost.order("published_at DESC").second
Although I think going with offset and limit is the somewhat cleaner and more portable version. Internally second (and third, fourth) use the find_nths method. Documented here:
http://apidock.com/rails/ActiveRecord/FinderMethods/second

How to turn on REGEXP in SQLite3 and Rails 3.1?

I have the following statement in Rails 3 using an SQLite3 database:
word = 'Hello'
word_entry = Word.where("name REGEXP :word", {:word => "[[:<:]]#{word}[[:>:]]"})
However, when running this under SQLite3, I keep getting:
SQLite3::SQLException: no such function: REGEXP
I read in the SQLite3 documentation that it does indeed support the REGEXP function.
In my gemfile, I have the line
gem 'sqlite3'
And my database config file looks like this:
development:
adapter: sqlite3
database: db/development.sqlite3
pool: 5
timeout: 5000
Any ideas what's going on?
RESOLUTION:
I ended up finding this solution. Unfortunately, it doesn't work for Rails 3.
So to use regular expressions I ended up switching to MYSQL instead of SQLite3.
I ran into the same issue. I took the code used in the resolution, ported it to work with Rails 3+ and made a gem for easier use. I hope this helps.
https://github.com/sei-mi/sqlite3_ar_regexp
From the fine manual:
The REGEXP operator is a special syntax for the regexp() user function. No regexp() user function is defined by default and so use of the REGEXP operator will normally result in an error message. If a application-defined SQL function named "regexp" is added at run-time, that function will be called in order to implement the REGEXP operator.
So the grammar supports REGEXP but the default SQLite library does not provide an implementation for it. You'll have to hook up your own implementation through some C wrangling if you want or need such a thing.
Presumably the rationale is that the SQLite people want to keep SQLite as small and tight as possible but including a whole regular expression library would add weight that most people don't want. Also, they would have to choose a regular expression library and include it with the SQLite source or they'd have to put up with the vagaries of everyone's regular expression support in libc. I'm not one of the SQLite developers so this is pure speculation.
I'm guessing that you'll probably have to make do with LIKE and GLOB. Using LIKE will provide a more portable solution.
You may be intested in the sqlite3-pcre package, which implements REGEXP for SQLite.
See this comment on a similar issue.
I had a similar question, and found a Gem named wherex that is well documented and worked out of the box.
Your expression from above
Word.where("name REGEXP :word", {:word => "[[:<:]]#{word}[[:>:]]"})
would there be
Word.where(:name => Regexp.new("[[:<:]]#{word}[[:>:]]"))
Works like a charm for me :-)
From source of sqlite3_ar_regexp project, I extract this:
db = SQLite3::Database.open( database_name )
db.create_function('regexp', 2) do |func, pattern, expression|
func.result = expression.to_s.match(
Regexp.new(pattern.to_s, Regexp::IGNORECASE)) ? 1 : 0
end
From source of sqlite3_ar_regexp project, I extract this:
db = ActiveRecord::Base.connection.raw_connection
db.create_function('regexp', 2) do |func, pattern, expression|
func.result = expression.to_s.match(
Regexp.new(pattern.to_s, Regexp::IGNORECASE)) ? 1 : 0
end
Improved upon a previous answer with ActiveRecord::Base.connection.raw_connection so that db name isn't needed