How to Twitter.update in Rails model - ruby-on-rails

I have a (cut-down) Model which looks like this:
class MyModel < ActiveRecord::Base
def self.update_status
event_time = time_ago_in_words 30.minutes.from_now
Twitter.update("Event is starting in #{event_time}")
end
end
As expected, I am getting a NoMethodError exception due to trying to use a method 'time_ago_in_words' from DateHelper. How should I accomplish this, and maybe more importantly, am I going about this the correct way?

extend ActionView::Helpers::DateHelper in your model
Change 30.mins.from_now to 30.minutes.from_now
I just tried it myself and have no problem doing the following:
class MyModel < ActiveRecord::Base
extend ActionView::Helpers::DateHelper
def self.update_status
event_time = time_ago_in_words(30.minutes.from_now)
Twitter.update("Event is starting in #{event_time}")
end
end
You have to use extend instead of include. See this article for an explanation.

Related

Search same class in Rails Model

Using Rails 3.2.17. I have the following in my model:
class Shop < ActiveRecord::Base
before_create :set_next_position
private
def set_next_position
self.position = self.class.where(country_id: country_id).
maximum(:position).to_i + 1
end
end
self is a Shop object. Note the line self.class.where... which is equivalent to Shop.where.... In this case, I don't know what is the best practice - to use Shop.where... or self.class.where...? It is code smell to me.
I would say self.class.where is better than Shop.where inside the class body. This way, you won't have to change inside, if for some reason you want to rename the class and so on.
The only difference that I now about is in case of inheritance. When you have:
class Base
def self.example
42
end
def run_example
Base.example
end
end
class A < Base
def self.example
'not 42'
end
end
A.new.run_example
=> 42
So when don't have inheritance I prefer Base.example. In the other case self.class.example.

Returning Module Class instead of Model Class with self.class Ruby/Rails

I am trying to DRY my code by implementing modules. However, I have constants stored in models (not the module) that I am trying to access with self.class.
Here are (I hope) the relevant snippets:
module Conversion
def constant(name_str)
self.class.const_get(name_str.upcase)
end
end
module DarkElixir
def dark_elixir(th_level)
structure.map { |name_str| structure_dark_elixir(name_str, th_level) if constant(name_str)[0][:dark_elixir_cost] }.compact.reduce(:+)
end
end
class Army < ActiveRecord::Base
include Conversion, DarkElixir
TH_LEVEL = [...]
end
def structure_dark_elixir(name_str, th_level)
name_sym = name_str.to_sym
Array(0..send(name_sym)).map { |level| constant(name_str)[level][:dark_elixir_cost] }.reduce(:+) * TH_LEVEL[th_level][sym_qty(name)]
end
When I place the structure_dark_elixir method inside the DarkElixir module, I get an error, "uninitialized constant DarkElixir::TH_LEVEL"
While if I place it inside the Army class, it finds the appropriate constant.
I believe it is because I am not scoping the self.constant_get correctly. I would like to keep the method in question in the module as other models need to run the method referencing their own TH_LEVEL constants.
How might I accomplish this?
Why not just use class methods?
module DarkElixir
def dark_elixir(th_level)
# simplified example
th_level * self.class.my_th_level
end
end
class Army < ActiveRecord::Base
include DarkElixir
def self.my_th_level
5
end
end
Ugh. Method in question uses two constants. It was the second constant that was tripping up, not the first. Added "self.class::" prior to the second constant--back in business.
def structure_dark_elixir(name_str, th_lvl)
name_sym = name_str.to_sym
Array(0..send(name_sym)).map { |level| constant(name_str)[level][:dark_elixir_cost] }.reduce(:+) * self.class::TH_LEVEL[th_lvl][sym_qty(name_str)]
end

ActiveModel serializer inheritance

say I have this serializer
class FooSerializer < ActiveModel::Serializer
attributes :this, :that, :the_other
def this
SomeThing.expensive(this)
end
def that
SomeThing.expensive(that)
end
def the_other
SomeThing.expensive(the_other)
end
end
Where the operations for the individual serialized values is somewhat expensive...
And then I have another serializer that whats to make use of that, but not return all of the members:
class BarSerializer < FooSerializr
attributes :the_other
end
This does not work... BarSerializer will still have this, that, and the_other...
How can I make use of inheritance but not automatically get the same attributes? I am looking for a solution other than module mixins.
Turns out the answer to this is to make use of the magic include_xxx? methods...
class BarSerializer < FooSerializer
def include_this?; false; end
def include_that?; false; end
end
This will make it only serialize "the_other"
Make the BarSerializer the parents class and put the method the_other in it. FooSerializer will inherits only the method and the attribute defined in BarSerializer.

rails callback before 'new' of a model?

I have a model base_table, and I have a extended_table which has extra properties to further extend my base_table. (I would have different extended_tables, to add different properties to my base_table, but that's non-related to the question I'm asking here).
The model definition for my base_table is like:
class BaseTable < ActiveRecord::Base
module BaseTableInclude
def self.included(base)
base.belongs_to :base_table, autosave:true, dependent: :destroy
# do something more when this module is included
end
end
end
And the model definition for my extended_table is like:
class TennisQuestionaire < ActiveRecord::Base
include BaseTable::BaseTableInclude
end
Now I what I want is the code below:
params = {base_table: {name:"Songyy",age:19},tennis_ball_num:3}
t = TennisQuestionaire.new(params)
When I created my t, I want the base_table to be instantiated as well.
One fix I can come up with, is to parse the params to create the base_table object, before TennisQuestionaire.new was called upon the params. It's something like having a "before_new" filter here. But I cannot find such kind of filter when I was reading the documentation.
Additionally, I think another way is to override the 'new' method. But this is not so clean.
NOTE: There's one method called accepts_nested_attributes_for, seems to do what I want, but it doesn't work upon a belongs_to relation.
Any suggestions would be appreciated. Thanks :)
After some trails&error, the solution is something like this:
class BaseTable < ActiveRecord::Base
module BaseTableInclude
def initialize(*args,&block)
handle_res = handle_param_args(args) { |params| params[:base_table] = BaseTable.new(params[:base_table]) }
super(*args,&block)
end
private
def handle_param_args(args)
return unless block_given?
if args.length > 0
params = args[0]
if (params.is_a? Hash) and params[:base_table].is_a? Hash
yield params
end
end
end
end
end

Call a method in model after find in Ruby on Rails

I would like to know if it is possible to call a method from a model after using find.
Something like after_save, but after_find.
Thank you,
Gabriel.
Nowadays ((26.04.2012) this is proper way (and working!) to do that:
class SomeClass < ActiveRecord::Base
after_find :do_something
def do_something
# code
end
end
Edit: For Rails >= 3, see the answer from #nothing-special-here
There is. Along with after_initialize, after_find is a special case, though. You have to define the method, after_find :some_method isn't enough. This should work, though:
class Post < ActiveRecord::Base
def after_find
# do something here
end
end
You can read more about it in the API.
Interestingly enough, this will call the method twice... learned that one the hard way.
class Post < ActiveRecord::Base
after_find :after_find
def after_find
# do something here
end
end
If you need the found object in your method:
class SomeClass < ActiveRecord::Base
after_find{ |o| do_something(o) }
def do_something(o)
# ...
end
end
More details here: http://guides.rubyonrails.org/active_record_callbacks.html#after-initialize-and-after-find

Resources