I'm writing the documentation about my Rails' project and I have a question.
I developed the notification's mechanism with the GoRails tutorial and the code is something like this, Me question is this is a controller or a model logic? I think controller logic but I am not sure
class EventNotification < Noticed::Base
deliver_by :database
def message
#group=Group.find(params[:group][:id])
#user=User.find(params[:user][:id])
#event=Event.find(params[:event][:id])
"#{#event.user.username} invite you in #{#event.title} into #{#group.name} click here to visit"
end
#
def url
group_event_path(Group.find(params[:group][:id]), Event.find(params[:event][:id]) )
end
end
Related
I'm trying to see if it's possible to inject or execute gem's before filters in the parent app model.
Example:
Gem's gem/app/controllers/test/application_controller.rb:
module Test
class ApplicationController < ActionController::Base
before_update :foo
def foo
puts 'test'
end
end
end
Parent's App business.rb:
class Business < ApplicationRecord
# should call foo before creating the record
# and execute the puts statement
end
When the application executes Business.create(params), the business model should be calling method foo from the gem and executes the puts statement. Currently, I have no way of making this call, b/c foo is not executing before the create method. So I am looking for a way to try and test this. Thanks
Edit 2:
The use case here is each some of the models in the parent apps contain columns created_by and updated_by. We want to update these columns to the user UID that's doing the action on the specific model. I know I can do before_update or before_create in the parents app, but we want to put these actions in the gem so multiple of our applications can use it. The gem we are using is a common gem we wrote that integrated in all our applications. Also, I know there are gems out there like Audit-trail, but we want it simpler.
https://stackoverflow.com/a/35605007/14524531
Pretty much is the same idea with this snippet here, except using it in a gem with multiple models. I hope this makes it more clear. Thanks!
I have decided to test it with a new gem and a clean rails app.
Gem
Gemfile
source 'https://rubygems.org'
gemspec
gem 'activerecord'
lib/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
before_save :foo
def foo
puts 'test'
end
end
Rails app
app/models/business.rb
class Business < ApplicationRecord
end
In rails console I call Business.create and the first output I get is test.
I need some help with my plugin. I want to extend ActiveRecord::Base with a method that initializes another method that can be called in the controller.
It will look like this:
class Article < ActiveRecord::Base
robot_catch :title, :text
...
end
My attempt at extending the ActiveRecord::Base class with robot_catch method looks like following. The function will initialize the specified attributes (in this case :title and :text) in a variable and use class_eval to make the robot? function available for the user to call it in the controller:
module Plugin
module Base
extend ActiveSupport::Concern
module ClassMethods
def robot_catch(*attr)
##robot_params = attr
self.class_eval do
def robot?(params_hash)
# Input is the params hash, and this function
# will check if the some hashed attributes in this hash
# correspond to the attribute values as expected,
# and return true or false.
end
end
end
end
end
end
ActiveRecord::Base.send :include, Plugin::Base
So, in the controller, this could be done:
class ArticlesController < ApplicationController
...
def create
#article = Article.new(params[:article])
if #article.robot? params
# Do not save this in database, but render
# the page as if it would have succeeded
...
end
end
end
My question is whether if I am right that robot_catch is class method. This function is to be called inside a model, as shown above. I wonder if I am extending the ActiveRecord::Base the right way. The robot? function is an instance method without any doubt.
I am using Rails 3.2.22 and I installed this plugin as a gem in another project where I want to use this functionality.
Right now, it only works if I specifically require the gem in the model. However, I want it the functionality to be included as a part of ActiveRecord::Base without requiring it, otherwise I'd have to require it in every model I want to use it, not particularly DRY. Shouldn't the gem be automatically loaded into the project on Rails start-up?
EDIT: Maybe callbacks (http://api.rubyonrails.org/classes/ActiveSupport/Callbacks/ClassMethods.html) would be a solution to this problem, but I do not know how to use it. It seems a bit obscure.
First, I would suggest you make sure that none of the many many built in Rails validators meet your needs.
Then if that's the case, what you actually want is a custom validator.
Building a custom validator is not as simple as it might seem, the basic class you'll build will have this structure:
class SpecialValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
# Fill this with your validation logic
# Add to record.errors if validation fails
end
end
Then in your model:
class Article < ActiveRecord::Base
validates :title, :text, special: true
end
I would strongly suggest making sure what you want is not already built, chances are it is. Then use resources like this or ruby guides resources to continue going down the custom validator route.
Answer
I found out the solution myself. Bundler will not autoload dependencies from a gemspec that my project uses, so I had to require all third party gems in an engine.rb file in the lib/ directory of my app in order to load the gems. Now everything is working as it should.
Second: the robot_catch method is a class method.
I was recommend in an earlier question to use a gem called Wisper. I am very happy to learn about it, as it is exactly the solution I'm looking for. What I can't understand from the documentation on Wisper is how listeners register themselves.
Here is my code:
app/models/subscription.rb
class Subscription < ActiveRecord::Base
include Wisper::Publisher
def some_method
# some code here
broadcast(:subscription_paused)
end
end
app/models/offer.rb
class Offer < ActiveRecord::Base
def subscription_paused
binding.pry # or whatever
end
end
So I'm not entirely sure about this part here. I've tried a variety of subscribing techniques, but I think it just comes down to me not really understanding this aspect of it:
config/initializers/wisper.rb
Wisper.subscribe(Offer.new)
I also tried, similar to the example in the Wiki:
subscription = Subscription.new
subscription.subscribe(Offer.new)
What am I missing here? (I'm not really sure if the above code should even go in an initializer.)
If the tables exists for Offer and Subscription model then the code should work.
Try this in the rails console:
# class Subscription < ActiveRecord::Base
class Subscription
include Wisper::Publisher
def some_method
# some code here
broadcast(:subscription_paused)
end
end
# class Offer < ActiveRecord::Base
class Offer
def subscription_paused
puts "jeijjj"
end
end
Wisper.subscribe(Offer.new)
Subscription.new.some_method
It should generate an output:
"jeijjj"
Mailboxer allows you to connect multiple models as in the example from the gem page. Mailboxer Github page
You can use Mailboxer in any other model and use it in several different models. If you have ducks and cylons in your application and you want to exchange messages as if they were the same, just add acts_as_messageable to each one and you will be able to send duck-duck, duck-cylon, cylon-duck and cylon-cylon messages.
How can we restrict messaging to only between duck-cylon and vice versa? So, only a duck can initiate a conversation and a cylon can reply? And, no duck-duck and cylon-cylon conversations are possible?
You could add a module to the models
class Duck < ActiveRecord::Base
acts_as_messageable
include mailboxer_filter
end
and
class Cylon < ActiveRecord::Base
acts_as_messageable
include mailboxer_filter
end
your module...
module MalboxerFilter
def initiator?
self.class == Duck
end
def replyer?
self.class == Cylon
end
def send_message_filtered(beta, body, subject)
self.send_message(beta, body, subject) if initiator? && beta.replyer?
end
def reply_to_sender_filtered(*args)
self.reply_to_sender(*args) if replyer?
end
end
Then use send_message_filtered and reply_to_sender_filtered in your app. This can be more sophisticated if you need it... perhaps raise an exception if a Cylon attempts to initiate a message or a Duck attempts to reply.
My project is about an online Mobile Shopping site.
I created search controller,and I use WHERE LIKE to do that:
def create
#result = Phone.where(['name LIKE ?', "%#{get}%" ])
render :index
end
private
def get
params[:keyword]
end
Now I want to exchange to Full-text-search.So have some gem to do that ? And how to code to searching by full-text-search ?
You can use elastic-search-rails gem for implementing full text search in your Rails application.
In your app/models/phone.rb:
require 'elasticsearch/model'
class Phone < ActiveRecord::Base
include Elasticsearch::Model
include Elasticsearch::Model::Callbacks
end
Phone.import
Then, in your controller:
#result = Phone.search('foobar').records
Here is a good tutorial on Getting Started with Elasticsearch on Rails that would help you. Another good SitePoint article that will help you get going is Full-Text Search in Rails with ElasticSearch.