I have two devise authentication models in my app and want to create a chat amongst them. Can someone help me write the connection for the users? Below is what I have. I wanted to check if I can have two connections reject the connections for different users based on their individual logins. Any help is appreciated.
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
identified_by :current_supplier
def connect
self.current_user = find_verified_user
self.current_supplier = find_verified_supplier
end
private
def find_verified_user
if current_user = env['warden'].user('user')
current_user
end
end
def find_verified_supplier
if current_supplier = env['warden'].user('supplier')
current_supplier
else
reject_unauthorized_connection
end
end
end
end
Adapting a bit from this tutorial:
# app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_supplier, :current_user
def connect
find_verified
end
protected
def find_verified
setup_user if verified_user
setup_supplier if verified_supplier
reject_unauthorized_connection unless [current_supplier, current_user].any?
end
def verified_user
cookies.signed['user.expires_at'].present? &&
cookies.signed['user.expires_at'] > Time.zone.now
end
def verified_supplier
cookies.signed['supplier.expires_at'].present? &&
cookies.signed['supplier.expires_at'] > Time.zone.now
end
def setup_supplier
self.current_supplier = Supplier.find_by(id: cookies.signed['supplier.id'])
logger.add_tags 'ActionCable', "#{current_supplier.model_name.name} #{current_supplier.id}"
end
def setup_user
self.current_user = User.find_by(id: cookies.signed['user.id'])
logger.add_tags 'ActionCable', "#{current_user.model_name.name} #{current_user.id}"
end
end
end
And:
# config/initializers/warden_hooks.rb
Warden::Manager.after_set_user do |user, auth, opts|
scope = opts[:scope]
auth.cookies.signed["#{scope}.id"] = user.id
auth.cookies.signed["#{scope}.expires_at"] = 30.minutes.from_now
end
Warden::Manager.before_logout do |_user, auth, opts|
scope = opts[:scope]
auth.cookies.signed["#{scope}.id"] = nil
auth.cookies.signed["#{scope}.expires_at"] = nil
end
Related
I have a helper_method that allows links to escape from a subdomain. However it is impacting my videos_controller, as it essentially seems to negate the 'current_event' method when not in the events controlller.
I've tried several dozen different ways over the last 4 days to make it so I can still escape my links from the subdomain, but still allow the videos_controller to work.
I think the best way to achieve this is to exclude the videos_controller from the helper method, but I'm not sure how (or if it is actually the best way forward - I'm obviously a noob!) Any suggestions please?! Relevant code below:
module UrlHelper
def url_for(options = nil)
if request.subdomain.present? and request.subdomain.downcase != 'www' and !options.nil? and options.is_a?(Hash) and options.has_key? :only_path and options[:only_path]
options[:only_path] = false
end
super
end
end
Videos_controller
def new
if current_event?
#video = current_event.videos.new
else
#video = Video.new
end
end
def create
if current_event.present?
#video = current_event.videos.new(params[:video])
#video.user_id = current_user.id
key = get_key_from_the_cloud
#video.key = key
else
#video = current_user.videos.new(params[:video])
#video.user_id = current_user.id
key = get_key_from_the_cloud
#video.key = key
end
if #video.save
flash[:success] = "Video uploaded!"
redirect_to root_url(subdomain: => current_event.name)
else
flash[:error] = "#{#video.errors.messages}"
render :new
end
end
current_event method
def current_event
if request.subdomain.present?
#event = Event.find_by_name(request.subdomain)
end
end
Did you take a look at this post yet?
You might want to create a new function test that only does something like
module UrlHelper
def test
puts "Test is called"
end
end
If that works you know its not including that fails but it has to be the method.
Otherwise you know the module is not included and you can narrow down the search.
I am trying to add a mixin to my controller dynamically depending on the request parameters like so :
# Controller
class QuantitiesController < Admin::BaseController
before_filter :extend_input_method, only: [:create, :new]
def extend_input_method
input_method = params[:input_method]
if input_method
send(:extend, "InputMethod::#{input_method.classify}".constantize)
end
end
end
# Mixin that gets included in the controller
module InputMethod::Single
include InputMethod::Helpers
def new
puts "CALLED #new" # Debug information
load_recent_entries
quantity
end
def create
#quantity = scoped_by_subject.new(process_attributes)
if #quantity.save
save_success
else
load_recent_entries
save_error
end
end
end
The new method never gets called but my template gets rendered without raising an exception, even if action_name is new and respond_to?("new") is true after extending the instance.
I'd like to understand why this isn't working and how I can achieve something similar.
This is the solution I came up with. It works for my needs.
class QuantitiesController < Admin::BaseController
before_filter :extend_input_method, only: [:create, :new]
def new
_new
end
def create
_create
end
private
def extend_input_method
input_method = params[:input_method]
extend(Dep.get("InputMethod::#{input_method.classify}")) if input_method
end
end
module InputMethod::Single
include InputMethod::Helpers
def _new
# Do stuff...
end
def _create
# Do stuff...
end
end
I have two tables for checking views (visits of the page) - views of pic (PhotoView) in gallery and photographers(PhotographerView).
Because these two models (and tables) are the same, I want to create a model for them - something like:
class Func < ActiveRecord::Base
def self.check_views(model_view, data)
last_view = model_viewView.where('ip_address = ? AND request_url = ?', request.remote_ip, request.url).order('created_at DESC').first
unless last_view
model_view+View.new(...).save
model_view.increment_counter(:views, data.id)
else
if (DateTime.now - last_view.created_at.to_datetime) > 1.day
model_view+View.new(...).save
model_view.increment_counter(:views, data.id)
end
end #comparing dates
end
end
and call this method like:
#photo = Photo.find(params[:id])
Func.check_views('Photo', #photo)
When I try use it with the way above, I'll get the error undefined method `check_views' for Func(Table doesn't exist):Class
Could you give me a help, how to make it work?
Thank you
You can use ActiveRecord::Concern and modules to move the common functionality into one place as follows:
module CheckViews
extend ActiveSupport::Concern
module ClassMethods
# all class methods go here, if you don't have any just leave it blank
end
def check_views(data)
last_view = where('ip_address = ? AND request_url = ?', request.remote_ip, request.url).order('created_at DESC').first
unless last_view
##views_class.new(...).save
increment_counter(:views, data.id)
else
if (DateTime.now - last_view.created_at.to_datetime) > 1.day
##views_class.new(...).save
increment_counter(:views, data.id)
end
end #comparing dates
end
end
class Photo < ActiveRecord::Base
include CheckViews
end
you can now do the following:
#photo = Photo.find(params[:id])
#photo.check_views
I'd be very tempted to do this as a module extending the classes which want the Views functionality. Something like the following ought to work; but it's entirely untested and entirely unlike anything I've ever done before so it may be completely buggy. Fair warning.
module CheckViews
def self.extended(host_class)
host_class.class_variable_set("##views_class", "#{host_class}View".constantize)
end
def check_views(data)
last_view = where('ip_address = ? AND request_url = ?', request.remote_ip, request.url).order('created_at DESC').first
unless last_view
##views_class.new(...).save
increment_counter(:views, data.id)
else
if (DateTime.now - last_view.created_at.to_datetime) > 1.day
##views_class.new(...).save
increment_counter(:views, data.id)
end
end #comparing dates
end
end
class Photo < ActiveRecord::Base
extend CheckViews
...
end
(extend adds all the instance methods of the target Module as class methods of the calling class; so Photo gains Photo.check_views(data), and self in that function is the class Photo.)
I want to perform the similar thing as from base64 photo and paperclip -Rails, but with Carrierwave.
Could anybody explain me using of base64 images in Carrierwave?
class ImageUploader < CarrierWave::Uploader::Base
class FilelessIO < StringIO
attr_accessor :original_filename
attr_accessor :content_type
end
before :cache, :convert_base64
def convert_base64(file)
if file.respond_to?(:original_filename) &&
file.original_filename.match(/^base64:/)
fname = file.original_filename.gsub(/^base64:/, '')
ctype = file.content_type
decoded = Base64.decode64(file.read)
file.file.tempfile.close!
decoded = FilelessIO.new(decoded)
decoded.original_filename = fname
decoded.content_type = ctype
file.__send__ :file=, decoded
end
file
end
The accepted answer did not worked for me (v0.9).
It seems to be a check that fails before the cache callback.
This implementation works:
class ImageUploader < CarrierWave::Uploader::Base
# Mimick an UploadedFile.
class FilelessIO < StringIO
attr_accessor :original_filename
attr_accessor :content_type
end
# Param must be a hash with to 'base64_contents' and 'filename'.
def cache!(file)
if file.respond_to?(:has_key?) && file.has_key?(:base64_contents) && file.has_key?(:filename)
local_file = FilelessIO.new(Base64.decode64(file[:base64_contents]))
local_file.original_filename = file[:filename]
extension = File.extname(file[:filename])[1..-1]
local_file.content_type = Mime::Type.lookup_by_extension(extension).to_s
super(local_file)
else
super(file)
end
end
end
class Bear < ActiveRecord::Base
def feed!
self.transaction do
raise Exception unless self.foods_eaten << Food.new(:name => "fish")
self.fed_at = Time.now
save!
end
end
end
class Hippo < ActiveRecord::Base
def wash!
self.transaction do
#soap.inventory -= 1
#soap.save!
self.washed_at = Time.now
save!
end
end
end
class ZookeeperController < ApplicationController
def chores
#zookeeper = Zookeeper.find(params[:id])
Animal.transaction do
begin
#hippo.wash!
#bear.feed! # => FAIL AT THIS LINE
#zookeeper.finished_at = Time.now
#zookeeper.save!
redirect_to chores_completed_path
rescue Exception => e
render "new_chores"
end
end
end
end
If Zookeeper#chores gets invoked and #bear.feed! fails and raises an exception, then will everything rollback?
Any other suggestions on how to improve this code are also welcome.
It seems like what I have to do is raise an ActiveRecord::Rollback manually, otherwise it won't work as expected. ActiveRecord::Rollback is the only one that won't cause your screen to dump. http://api.rubyonrails.org/classes/ActiveRecord/Rollback.html
It makes sense that it would work like this, but wasn't really how I intuitively thought it would work. Please correct me if I'm wrong.
So the new code would look something like this:
class ZookeeperController < ApplicationController
def chores
#zookeeper = Zookeeper.find(params[:id])
Animal.transaction do
begin
#hippo.wash!
#bear.feed! # => FAIL AT THIS LINE
#zookeeper.finished_at = Time.now
#zookeeper.save!
redirect_to chores_completed_path
rescue Exception => e
#_errors = true
render "new_chores"
end
raise ActiveRecord::Rollback if #_errors
end
end
end