How to load extra fields into a model from thinking-sphinx? - ruby-on-rails

I use thinking-sphinx like this :
class Project < ActiveRecord::Base
define_index do
indexes title
indexes comments.message, as: :comment_message
indexes category_projects.description, as: :category_description
end
class << self
def text_search(word)
ThinkingSphinx.search(word, include: :comments)
end
end
end
When I do this Project.text_search('test') it works but I want to do this :
#projects = Project.text_search('test')
#projects.each do |project|
puts project.comment_message
end
For the moment I have this message :
undefined method `comment_message' for #<ThinkingSphinx::Search:0x000000057e11c0>
from /home/dougui/.rvm/gems/ruby-1.9.3-p194-perf#comment_my_projects/bundler/gems/thinking-sphinx-b293abdbdf0c/lib/thinking_sphinx/search.rb:185:in `method_missing'
from (irb):1
from /home/dougui/.rvm/gems/ruby-1.9.3-p194-perf#comment_my_projects/gems/railties-3.2.6/lib/rails/commands/console.rb:47:in `start'
from /home/dougui/.rvm/gems/ruby-1.9.3-p194-perf#comment_my_projects/gems/railties-3.2.6/lib/rails/commands/console.rb:8:in `start'
from /home/dougui/.rvm/gems/ruby-1.9.3-p194-perf#comment_my_projects/gems/railties-3.2.6/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
So, how to load fields into a model from thinking-sphinx?
I didn't find anything one the doc.
Thanks!

Answered on the TS mailing list as well, but essentially, the fields aren't returned by Sphinx, so you just need to refer to the associations/columns that the fields are built from:
projects.each do |project|
puts project.comments.message.join("\n")
end

Related

Elasticsearch - undefined method `as_indexed_json'

I'm able to do the bare bones keyword search with no issues in my app using elasticsearch, but as_indexed_json isn't working apparently and I have no idea why. I'm following this tutorial, and the section in question is almost halfway down.
Please let me know if I need to provide any additional info. I'm pretty new to this, so I apologize if this is a really dumb question.
Rails console:
2.2.4 :011 > Term.first.as_indexed_json
Term Load (0.4ms) SELECT "terms".* FROM "terms" ORDER BY "terms"."id" ASC LIMIT 1
NoMethodError: undefined method `as_indexed_json' for #<Term:0x007fa6cd9a6408>
from /Users/emplumb/.rvm/gems/ruby-2.2.4/gems/activemodel-4.2.5/lib/active_model/attribute_methods.rb:433:in `method_missing'
from (irb):11
from /Users/emplumb/.rvm/gems/ruby-2.2.4/gems/railties-4.2.5/lib/rails/commands/console.rb:110:in `start'
from /Users/emplumb/.rvm/gems/ruby-2.2.4/gems/railties-4.2.5/lib/rails/commands/console.rb:9:in `start'
from /Users/emplumb/.rvm/gems/ruby-2.2.4/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:68:in `console'
from /Users/emplumb/.rvm/gems/ruby-2.2.4/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
from /Users/emplumb/.rvm/gems/ruby-2.2.4/gems/railties-4.2.5/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
Model:
require 'elasticsearch/model'
class Term < ActiveRecord::Base
include Elasticsearch::Model
include Elasticsearch::Model::Callbacks
def as_indexed_json(options = {})
as_json(
only: [:name, :definition, :etymology1, :etymology2, :uses, :romance_cognates, :notes1, :notes2, :quote1, :quote2]
)
end
end
Based on that tutorial i hope you opened the irb using rails c.
But open console like this bundle exec rails c and try again

my_zipcode_gem migration generators not working

I'm pretty sure that the problem is due to the fact that this gem looks to be 3-4 years old and rails has changed how we do migrations. But I'm not too familiar with gems/generators. I'm trying to follow the instructions to do the instructions listed here.
rails g my_zipcode_gem:models
rake db:migrate
rake zipcodes:update
However, when I do the first step I end up getting this:
/Users/thammond/.rvm/gems/ruby-2.1.1/gems/my_zipcode_gem-0.1.3/lib/generators/my_zipcode_gem/models_generator.rb:35:in `create_migration': wrong number of arguments (3 for 0) (ArgumentError)
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/railties-4.1.0/lib/rails/generators/migration.rb:63:in `migration_template'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/my_zipcode_gem-0.1.3/lib/generators/my_zipcode_gem/models_generator.rb:36:in `create_migration'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/thor-0.19.1/lib/thor/command.rb:27:in `run'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/thor-0.19.1/lib/thor/invocation.rb:126:in `invoke_command'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/thor-0.19.1/lib/thor/invocation.rb:133:in `block in invoke_all'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/thor-0.19.1/lib/thor/invocation.rb:133:in `each'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/thor-0.19.1/lib/thor/invocation.rb:133:in `map'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/thor-0.19.1/lib/thor/invocation.rb:133:in `invoke_all'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/thor-0.19.1/lib/thor/group.rb:232:in `dispatch'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/thor-0.19.1/lib/thor/base.rb:440:in `start'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/railties-4.1.0/lib/rails/generators.rb:157:in `invoke'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/railties-4.1.0/lib/rails/commands/generate.rb:11:in `<top (required)>'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `require'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `block in require'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.0/lib/active_support/dependencies.rb:232:in `load_dependency'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `require'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/railties-4.1.0/lib/rails/commands/commands_tasks.rb:135:in `generate_or_destroy'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/railties-4.1.0/lib/rails/commands/commands_tasks.rb:51:in `generate'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/railties-4.1.0/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
from /Users/thammond/.rvm/gems/ruby-2.1.1/gems/railties-4.1.0/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
Any idea what I need to do to get that gem working? It provides exactly what I'm looking for in my app.
Thanks!
Edit: Adding the generation code:
module MyZipcodeGem
class ModelsGenerator < Base
include Rails::Generators::Migration
source_root File.expand_path('../templates', __FILE__)
def initialize(*args, &block)
super
end
def generate_models
# puts ">>> generate_zipcodes:"
end
def add_gems
add_gem "mocha", :group => :test
end
def create_models
template 'zipcode_model.rb', "app/models/zipcode.rb"
template 'county_model.rb', "app/models/county.rb"
template 'state_model.rb', "app/models/state.rb"
end
# Implement the required interface for Rails::Generators::Migration.
# taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
def self.next_migration_number(dirname)
if ActiveRecord::Base.timestamped_migrations
Time.now.utc.strftime("%Y%m%d%H%M%S")
else
"%.3d" % (current_migration_number(dirname) + 1)
end
end
def create_migration
migration_template 'migration.rb', "db/migrate/create_my_zipcode_gem_models.rb"
end
def create_rakefile
template 'zipcodes.rake', "lib/tasks/zipcodes.rake"
end
end
end
# /Users/cblackburn/.rvm/gems/ruby-1.9.2-p136/gems/activerecord-3.0.3/lib/rails/generators/active_record/
It looks like it is calling the migration using parameters that are no longer expected. You have two options:
1) fork the code, update it to use rails 4 conventions, and create a pull request on github. Assuming the owner is still active they will bring your code into the master and republish the gem. You would have help support the community and feel good about it in the process. There are plenty on here like myself who can help you with this.
2) Find another gem to do what you want, such as http://www.rubygeocoder.com/ which I've used several times and is awesome at doing location/zipcode problems

Rails monkey patch only on certain columns

I am trying to include a module only if the subclass has a certain column,
and I am doing this in an initializer:
class ActiveRecord::Base
def self.inherited(subclass)
subclass.include(MultiTenancy) if subclass.new.respond_to?(:tenant_id)
end
end
I keep getting this error:
NoMethodError: undefined method `[]' for nil:NilClass
Here is the module that I am importing:
module MultiTenancy
class TenantNotSetError < StandardError ; end
def self.included(model)
model.class_eval do
belongs_to :tenant
validates :tenant_id, presence: true
default_scope -> {
raise TenantNotSetError.new unless Tenant.current_tenant
where(tenant_id: Tenant.current_tenant.id)
}
def multi_tenanted?
true
end
end
end
end
What am I doing wrong. I can include the module on any subclass separate eg. Klass.include(MultiTenancy) successfully, so the problem is with the initializer.
Below is the stack trace:
from -e:1:in `<main>'2.1.1 :002 > Klass.all
NoMethodError: undefined method `[]' for nil:NilClass
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activerecord-4.1.4/lib/active_record/relation/delegation.rb:9:in `relation_delegate_class'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activerecord-4.1.4/lib/active_record/relation/delegation.rb:112:in `relation_class_for'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activerecord-4.1.4/lib/active_record/relation/delegation.rb:106:in `create'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activerecord-4.1.4/lib/active_record/model_schema.rb:133:in `table_name='
from /home/lee/Code/mobifit/app/models/klass.rb:25:in `<class:Klass>'
from /home/lee/Code/mobifit/app/models/klass.rb:22:in `<top (required)>'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:443:in `load'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:443:in `block in load_file'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:633:in `new_constants_in'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:442:in `load_file'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:342:in `require_or_load'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:480:in `load_missing_constant'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:180:in `const_missing'
from (irb):2
from /home/lee/.rvm/gems/ruby-2.1.1/gems/railties-4.1.4/lib/rails/commands/console.rb:90:in `start'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/railties-4.1.4/lib/rails/commands/console.rb:9:in `start'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/railties-4.1.4/lib/rails/commands/commands_tasks.rb:69:in `console'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/railties-4.1.4/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/railties-4.1.4/lib/rails/commands.rb:17:in `<top (required)>'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:247:in `require'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:247:in `block in require'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:232:in `load_dependency'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:247:in `require'
from /home/lee/Code/mobifit/bin/rails:8:in `<top (required)>'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:241:in `load'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:241:in `block in load'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:232:in `load_dependency'
from /home/lee/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:241:in `load'
from /home/lee/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /home/lee/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from -e:1:in `<main>'2.1.1 :003 >
If you follow the stack trace back a bit, you can see that the thing that's nil that isn't supposed to be is is the class's #relation_delegate_cache. Looking at the source, you can see that this normally gets initialized in the initialize_relation_delegate_cache method, which is called in the inherited hook for ActiveRecord::Delegation::DelegateCache.
ActiveRecord::Base extends this module, so normally a class that inherits from ActiveRecord::Base would call this inherited hook. So the problem with your code is that you're monkey-patching inherited on ActiveRecord::Base, which means that the hook in ActiveRecord::Delegation::DelegateCache is no longer being called.
Two comments:
This is why it's a bad idea to monkey-patch, especially something as fundamental and complex as active record. Is it possible to do what you want to do in a more straightforward way?
If it's not, you should take some notes on how ActiveRecord::Delegation::DelegateCache works and rewrite your monkey patch to mix in a module of your own, rather than just over-writing ActiveRecord::Base's inherited method.
The suggestion in (2) would look something like this:
module MultitenancyConcern
def self.inherited(subclass)
subclass.include(MultiTenancy) if subclass.column_names.include?("tenant_id")
super #this is critical for avoiding the error you're getting
end
end
then your monkey-patch becomes just
ActiveRecord::Base.extend(MultitenancyConcern)

Rails before_destory only works with destroy and not with delete

I am building a rails applications, where in a part of it, I save to the database, payments information. I need to make these payments un-deleteable.
I have created a before_destroy function that kinda works.. but I am having an issue:
here is my code:
class StripePayment < ActiveRecord::Base
belongs_to :user
belongs_to :stripe_card
before_destroy :fail
private
def fail
return false
end
end
When I create a payment and try out my code when delete:
StripePayment.first.destroy returns false and rollback... Which is exactly what I want.
However,
StripePayment.first.delete passes and deletes the object.
I know the deference between delete and destroy. however, I want to be able to prevent this object from being deleted on the DB (on both delete() and destroy() calls.
I tried before_delete and rails gave me back this error:
NoMethodError: undefined method `before_delete' for #<Class:0x007fc1abc37c50>
from /Users/alybadawy/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.0/lib/active_record/dynamic_matchers.rb:22:in `method_missing'
from /Users/alybadawy/developing/repos/finish/finish/app/models/stripe_payment.rb:7:in `<class:StripePayment>'
from /Users/alybadawy/developing/repos/finish/finish/app/models/stripe_payment.rb:1:in `<top (required)>'
from /Users/alybadawy/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-4.0.0/lib/active_support/dependencies.rb:423:in `load'
from /Users/alybadawy/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-4.0.0/lib/active_support/dependencies.rb:423:in `block in load_file'
from /Users/alybadawy/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-4.0.0/lib/active_support/dependencies.rb:615:in `new_constants_in'
from /Users/alybadawy/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-4.0.0/lib/active_support/dependencies.rb:422:in `load_file'
from /Users/alybadawy/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-4.0.0/lib/active_support/dependencies.rb:323:in `require_or_load'
from /Users/alybadawy/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-4.0.0/lib/active_support/dependencies.rb:462:in `load_missing_constant'
from /Users/alybadawy/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-4.0.0/lib/active_support/dependencies.rb:183:in `const_missing'
from (irb):1
from /Users/alybadawy/.rvm/gems/ruby-2.0.0-p247/gems/railties-4.0.0/lib/rails/commands/console.rb:90:in `start'
from /Users/alybadawy/.rvm/gems/ruby-2.0.0-p247/gems/railties-4.0.0/lib/rails/commands/console.rb:9:in `start'
from /Users/alybadawy/.rvm/gems/ruby-2.0.0-p247/gems/railties-4.0.0/lib/rails/commands.rb:64:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
Any help will be appreciated. Thanks :)
The easiest way is, to define your own delete method
class StripePayment < ActiveRecord::Base
belongs_to :user
belongs_to :stripe_card
before_destroy :fail
def delete
false
end
private
def fail
return false
end
end
If you have conditions, where you want to allow deleteion, you can check for it iy your delete method and call super
that's because delete is one of the functions that skips callbacks in rails
check this out for more info on the subject http://edgeguides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks

ActiveRecord custom attributes

How can I assign a custom attribute to an ActiveRecord model?
For example, I can do it when querying via:
select("(CASE WHEN wishlist_items.id IS null THEN 0 ELSE 1 END) AS is_wishlisted_by_me").
This adds a custom is_wishlisted_by_me attribute. But what if I already have an instance of an AR model and I want to do:
model.is_wishlisted_by_me = true
this returns a NoMethodError: undefined method
NoMethodError: undefined method `is_wishlisted_by_me=' for #<SIImage:0x007fc8c41c7ef8>
from /Users/Test/.rvm/gems/ruby-1.9.3-p327/gems/activemodel-3.2.13/lib/active_model/attribute_methods.rb:407:in `method_missing'
from /Users/Test/.rvm/gems/ruby-1.9.3-p327/gems/activerecord-3.2.13/lib/active_record/attribute_methods.rb:149:in `method_missing'
from (irb):8
from /Users/Test/.rvm/gems/ruby-1.9.3-p327/gems/railties-3.2.13/lib/rails/commands/console.rb:47:in `start'
from /Users/Test/.rvm/gems/ruby-1.9.3-p327/gems/railties-3.2.13/lib/rails/commands/console.rb:8:in `start'
from /Users/Test/.rvm/gems/ruby-1.9.3-p327/gems/railties-3.2.13/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
I think you can do it with this way, define attr_accessible in your model:
attr_accessible :user_count
r = User.find_by_sql("select count(*) as user_count from users")
puts r.first.user_count
If a hash will do for you, you may try
User.connection.select_all("select count(*) as user_count from users")
which will return an array of hash like [{:user_count => 1}]
This is what I've done:
after_initialize do
self.is_wishlisted_by_me = nil unless #attributes.key?("is_wishlisted_by_me")
end
def is_wishlisted_by_me
#attributes["is_wishlisted_by_me"]
end
def is_wishlisted_by_me=(value)
#attributes["is_wishlisted_by_me"] = value
end

Resources