flyerhzm / switch_user Goto Github PK
View Code? Open in Web Editor NEWEasily switch current user
License: MIT License
Easily switch current user
License: MIT License
My Admins log in on one subdomain (admin), but the Users that they can impersonate use a subdomain that depends on their account (multi-tenant setup).
I haven't been able to coax switch_user to be able to redirect to the proper subdomain. In fact, my changes there seem to have no effect at all.
In my initializer, I have:
config.redirect_path = lambda { |request, params| authenticated_root_url(subdomain: current_user.subdomain) }
I realize that current_user probably isn't in scope, but I don't even this this code is being hit...
My logs (on attempting to switch user) look like the following:
[admin] Started GET "/switch_user?scope_identifier=user_5" for 127.0.0.1 at 2013-06-06 16:41:06 +0200
[admin] Processing by SwitchUserController#set_current_user as HTML
[admin] Parameters: {"scope_identifier"=>"user_5"}
[admin] Completed 401 Unauthorized in 4ms
[admin]
[admin]
[admin] Started GET "/users/sign_in" for 127.0.0.1 at 2013-06-06 16:41:06 +0200
[admin]
ActionController::RoutingError (No route matches [GET] "/users/sign_in"):
It makes sense that the route is not found (it's based on a route constraint), but in general, I'm unsure of how to get this to work.
Any tips?
I'm a bit confused by the "Completed 401 Unauthorized" at GET /switch_user
The fact that switch_user offers routes, controllers and some view code makes it an ideas candidate for being a rails engine. This would make it easy to add an initializer with some good default configuration options.
I'm motivated to make this happen, but I want to ensure that I'm not taking the project in a direction that you never intended.
The less good news is that I'm thinking about deprecating rails 2 support moving forward with the project as keeping rails 2 compatibility on new releases could hamper progress and would certainly make implementing the engine feature more difficult.
I respect that some people still use rails 2 and I have a couple projects that use it too. So, for the rails 2 users we would:
Tell me what you think or just tell me to go for it.
Luke
I rolled my own authentication (based on ryan bates' casts). What provider should I put?
I see that devise is the default, which obviously I'm not using so I get an unknown method 'warden' error.
Hello,
My user is under a module so I made the changes in config file as follows:
config.available_users = { :"MyModule::User" => lambda { MyModule::User.all } }
And when I switch the user I find that warden is scoped to MyModule::User for logout and login which is not working. If I remove the scope from line no. 10 and 14 of devise.rb file @warden.set_user(user, :scope => scope) & @warden.logout(scope) respectively then it is working.
Any help is appreciated.
Thanks in advance.
We use "members" instead of "users". It'd be nice to be able to implement this gem easily.
config.switch_back = true
config.controller_guard = lambda { |current_user, request, original_user|
current_user && current_user.admin? || original_user && original_user.super_admin?
}
I want to do current_user.has_role? :admin ||original_user && original_user.has_role? :admin. I have no super admin. How do I do this? I am not able to do it. If I try the original I get
NoMethodError - undefined method `admin?' for #User:0x007fbd44cc34f0:
If I tried this modified version of it
config.controller_guard = lambda { |current_user, request, original_user|
current_user && current_user.has_role? :admin || original_user && original_user.has_role? :admin}
I get errors like
config/initializers/switch_user.rb:59: syntax error, unexpected tSYMBEG, expecting '}' (SyntaxError)
...ser && current_user.has_role? :admin || original_user && ori...
... ^
/home/aravind/Documents/dev/gw-c4u/config/initializers/switch_user.rb:59: syntax error, unexpected tSYMBEG, expecting '}'
...er && original_user.has_role? :admin}
I've been chatting with @assembler about how to evolve the API in the project without breaking backwards compatibility. Without getting in to anything to specific, here's how I'm thinking about introducing changes:
We introducing a stable and development branch for switch user. The stable branch can get bug fixes and additional providers and we can use the development branch to evolve the API and improve the design. The next stable release would be 0.9.2 and the next dev release would be 0.10.0.
Hopefully people have specified something like ~>0.9.0 in their gemfile and if not, we can make some noise on startup and tell them how to fix it.
This is your chance to weigh in with your thoughts and experience.
If I let only priviledged users to switch accounts, as soon as they switch it, there is no way to "switch back". It would be nice if the original user is stored somewhere in the session and that the user can "switch back"
Hello,
I don't want to use the switch_user_select
(because we have too many users, and it does not fit the way we're doing things). Instead, I'm generating a switch user link, as described in the README:
= link_to "Sign in as #{user.login}", "/switch_user?scope_identifier=user_#{user.id}"
How can I enable the switch back feature, and allow a user to switch back to their previous login, if they used the link above to switch, in the first place?
Is there something I could do to save the original user, and then check if present, to allow switch back?
Thanks for your help,
David
Hi,
I've tried to integrate switch_user to our 1.9.2 app and unfortunately have had some problems. When the app starts, it shows me the following error:
ActionView::Template::Error (wrong number of arguments (2 for 0)):
8: %li.separated= link_to t(:admin), edit_company_path(current_user.company), :title => current_user.company.name
9: %li.separated= link_to t(:logout), destroy_user_session_path
10: %li
11: %li= switch_user_select
12: %li
13: %li= link_to t(:help), '', :class => 'help'
14: - else # otherwise, show signup and login
config/initializers/switch_user.rb:2:in `block in <top (required)>'
switch_user (0.6.0) app/helpers/switch_user_helper.rb:35:in `call'
switch_user (0.6.0) app/helpers/switch_user_helper.rb:35:in `available?'
switch_user (0.6.0) app/helpers/switch_user_helper.rb:3:in `switch_user_select'
app/views/shared/_user_nav.html.haml:11:in `_app_views_shared__user_nav_html_haml__4230259447007091948_2193152860_2749566956400468611'
actionpack (3.0.3) lib/action_view/template.rb:135:in `block in render'
activesupport (3.0.3) lib/active_support/notifications.rb:54:in `instrument'
actionpack (3.0.3) lib/action_view/template.rb:127:in `render'
actionpack (3.0.3) lib/action_view/render/partials.rb:333:in `render_partial'
actionpack (3.0.3) lib/action_view/render/partials.rb:262:in `block in render'
activesupport (3.0.3) lib/active_support/notifications.rb:52:in `block in instrument'
activesupport (3.0.3) lib/active_support/notifications/instrumenter.rb:21:in `instrument'
activesupport (3.0.3) lib/active_support/notifications.rb:52:in `instrument'
actionpack (3.0.3) lib/action_view/render/partials.rb:260:in `render'
actionpack (3.0.3) lib/action_view/render/partials.rb:378:in `_render_partial'
actionpack (3.0.3) lib/action_view/render/rendering.rb:22:in `render'
haml (3.0.22) lib/haml/helpers/action_view_mods.rb:11:in `block in render_with_haml'
haml (3.0.22) lib/haml/helpers.rb:90:in `non_haml'
haml (3.0.22) lib/haml/helpers/action_view_mods.rb:11:in `render_with_haml'
app/views/layouts/application.html.haml:31:in `_app_views_layouts_application_html_haml__3711706665586214582_2207711080_2202985393179614085'
actionpack (3.0.3) lib/action_view/template.rb:135:in `block in render'
activesupport (3.0.3) lib/active_support/notifications.rb:54:in `instrument'
actionpack (3.0.3) lib/action_view/template.rb:127:in `render'
actionpack (3.0.3) lib/action_view/render/layouts.rb:80:in `_render_layout'
actionpack (3.0.3) lib/action_view/render/rendering.rb:62:in `block in _render_template'
activesupport (3.0.3) lib/active_support/notifications.rb:52:in `block in instrument'
activesupport (3.0.3) lib/active_support/notifications/instrumenter.rb:21:in `instrument'
activesupport (3.0.3) lib/active_support/notifications.rb:52:in `instrument'
actionpack (3.0.3) lib/action_view/render/rendering.rb:56:in `_render_template'
actionpack (3.0.3) lib/action_view/render/rendering.rb:26:in `render'
haml (3.0.22) lib/haml/helpers/action_view_mods.rb:13:in `render_with_haml'
actionpack (3.0.3) lib/abstract_controller/rendering.rb:114:in `_render_template'
actionpack (3.0.3) lib/abstract_controller/rendering.rb:108:in `render_to_body'
actionpack (3.0.3) lib/action_controller/metal/renderers.rb:47:in `render_to_body'
actionpack (3.0.3) lib/action_controller/metal/compatibility.rb:55:in `render_to_body'
actionpack (3.0.3) lib/abstract_controller/rendering.rb:101:in `render_to_string'
actionpack (3.0.3) lib/abstract_controller/rendering.rb:92:in `render'
actionpack (3.0.3) lib/action_controller/metal/rendering.rb:17:in `render'
actionpack (3.0.3) lib/action_controller/metal/instrumentation.rb:40:in `block (2 levels) in render'
activesupport (3.0.3) lib/active_support/core_ext/benchmark.rb:5:in `block in ms'
/Users/khelal/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/1.9.1/benchmark.rb:309:in `realtime'
activesupport (3.0.3) lib/active_support/core_ext/benchmark.rb:5:in `ms'
actionpack (3.0.3) lib/action_controller/metal/instrumentation.rb:40:in `block in render'
actionpack (3.0.3) lib/action_controller/metal/instrumentation.rb:78:in `cleanup_view_runtime'
activerecord (3.0.3) lib/active_record/railties/controller_runtime.rb:15:in `cleanup_view_runtime'
actionpack (3.0.3) lib/action_controller/metal/instrumentation.rb:39:in `render'
vendor/plugins/active_scaffold/lib/extensions/action_controller_rendering.rb:13:in `render_with_active_scaffold'
actionpack (3.0.3) lib/action_controller/metal/implicit_render.rb:10:in `default_render'
actionpack (3.0.3) lib/action_controller/metal/implicit_render.rb:5:in `send_action'
actionpack (3.0.3) lib/abstract_controller/base.rb:151:in `process_action'
actionpack (3.0.3) lib/action_controller/metal/rendering.rb:11:in `process_action'
actionpack (3.0.3) lib/abstract_controller/callbacks.rb:18:in `block in process_action'
activesupport (3.0.3) lib/active_support/callbacks.rb:465:in `_run__2906524511501775473__process_action__125179480482283175__callbacks'
activesupport (3.0.3) lib/active_support/callbacks.rb:409:in `_run_process_action_callbacks'
activesupport (3.0.3) lib/active_support/callbacks.rb:93:in `run_callbacks'
actionpack (3.0.3) lib/abstract_controller/callbacks.rb:17:in `process_action'
actionpack (3.0.3) lib/action_controller/metal/instrumentation.rb:30:in `block in process_action'
activesupport (3.0.3) lib/active_support/notifications.rb:52:in `block in instrument'
activesupport (3.0.3) lib/active_support/notifications/instrumenter.rb:21:in `instrument'
activesupport (3.0.3) lib/active_support/notifications.rb:52:in `instrument'
actionpack (3.0.3) lib/action_controller/metal/instrumentation.rb:29:in `process_action'
actionpack (3.0.3) lib/action_controller/metal/rescue.rb:17:in `process_action'
actionpack (3.0.3) lib/abstract_controller/base.rb:120:in `process'
actionpack (3.0.3) lib/abstract_controller/rendering.rb:40:in `process'
actionpack (3.0.3) lib/action_controller/metal.rb:138:in `dispatch'
actionpack (3.0.3) lib/action_controller/metal/rack_delegation.rb:14:in `dispatch'
actionpack (3.0.3) lib/action_controller/metal.rb:178:in `block in action'
actionpack (3.0.3) lib/action_dispatch/routing/route_set.rb:62:in `call'
actionpack (3.0.3) lib/action_dispatch/routing/route_set.rb:62:in `dispatch'
actionpack (3.0.3) lib/action_dispatch/routing/route_set.rb:27:in `call'
rack-mount (0.6.13) lib/rack/mount/route_set.rb:148:in `block in call'
rack-mount (0.6.13) lib/rack/mount/code_generation.rb:93:in `block in recognize'
rack-mount (0.6.13) lib/rack/mount/code_generation.rb:68:in `optimized_each'
rack-mount (0.6.13) lib/rack/mount/code_generation.rb:92:in `recognize'
rack-mount (0.6.13) lib/rack/mount/route_set.rb:139:in `call'
actionpack (3.0.3) lib/action_dispatch/routing/route_set.rb:492:in `call'
haml (3.0.22) lib/sass/plugin/rack.rb:41:in `call'
warden (0.10.7) lib/warden/manager.rb:35:in `block in call'
warden (0.10.7) lib/warden/manager.rb:34:in `catch'
warden (0.10.7) lib/warden/manager.rb:34:in `call'
actionpack (3.0.3) lib/action_dispatch/middleware/best_standards_support.rb:17:in `call'
actionpack (3.0.3) lib/action_dispatch/middleware/head.rb:14:in `call'
rack (1.2.1) lib/rack/methodoverride.rb:24:in `call'
actionpack (3.0.3) lib/action_dispatch/middleware/params_parser.rb:21:in `call'
actionpack (3.0.3) lib/action_dispatch/middleware/flash.rb:182:in `call'
actionpack (3.0.3) lib/action_dispatch/middleware/session/abstract_store.rb:149:in `call'
actionpack (3.0.3) lib/action_dispatch/middleware/cookies.rb:295:in `call'
activerecord (3.0.3) lib/active_record/query_cache.rb:32:in `block in call'
activerecord (3.0.3) lib/active_record/connection_adapters/abstract/query_cache.rb:28:in `cache'
activerecord (3.0.3) lib/active_record/query_cache.rb:12:in `cache'
activerecord (3.0.3) lib/active_record/query_cache.rb:31:in `call'
activerecord (3.0.3) lib/active_record/connection_adapters/abstract/connection_pool.rb:353:in `call'
actionpack (3.0.3) lib/action_dispatch/middleware/callbacks.rb:46:in `block in call'
activesupport (3.0.3) lib/active_support/callbacks.rb:415:in `_run_call_callbacks'
actionpack (3.0.3) lib/action_dispatch/middleware/callbacks.rb:44:in `call'
rack (1.2.1) lib/rack/sendfile.rb:107:in `call'
actionpack (3.0.3) lib/action_dispatch/middleware/remote_ip.rb:48:in `call'
actionpack (3.0.3) lib/action_dispatch/middleware/show_exceptions.rb:46:in `call'
railties (3.0.3) lib/rails/rack/logger.rb:13:in `call'
rack (1.2.1) lib/rack/runtime.rb:17:in `call'
activesupport (3.0.3) lib/active_support/cache/strategy/local_cache.rb:72:in `call'
rack (1.2.1) lib/rack/lock.rb:11:in `block in call'
<internal:prelude>:10:in `synchronize'
rack (1.2.1) lib/rack/lock.rb:11:in `call'
actionpack (3.0.3) lib/action_dispatch/middleware/static.rb:30:in `call'
railties (3.0.3) lib/rails/application.rb:168:in `call'
railties (3.0.3) lib/rails/application.rb:77:in `method_missing'
railties (3.0.3) lib/rails/rack/log_tailer.rb:14:in `call'
rack (1.2.1) lib/rack/content_length.rb:13:in `call'
rack (1.2.1) lib/rack/handler/webrick.rb:52:in `service'
/Users/khelal/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/1.9.1/webrick/httpserver.rb:111:in `service'
/Users/khelal/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/1.9.1/webrick/httpserver.rb:70:in `run'
/Users/khelal/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/1.9.1/webrick/server.rb:183:in `block in start_thread'
I'd like to extract the logic for loading a user rout of the controller. The interface would be something like:
SwitchUser::LoadsUser.from_identifier(scope, id)
returns a user if there's a user and nil otherwise
raises an exception if the user has requested an unavailable scope
allow more of the code base to be easily tested
Any input you have is welcome. If it sounds good, I'll send another pull request.
Here is my config initializer:
SwitchUser.setup do |config|
# provider may be :devise, :authlogic, :clearance, :restful_authentication, :sorcery, or :session
config.provider = :devise
# available_users is a hash,
# key is the model name of user (:user, :admin, or any name you use),
# value is a block that return the users that can be switched.
config.available_users = { :athlete => lambda { Athlete.all } }
# available_users_identifiers is a hash,
# keys in this hash should match a key in the available_users hash
# value is the name of the identifying column to find by,
# defaults to id
# this hash is to allow you to specify a different column to
# expose for instance a username on a User model instead of id
config.available_users_identifiers = { :athlete => :id }
# available_users_names is a hash,
# keys in this hash should match a key in the available_users hash
# value is the column name which will be displayed in select box
config.available_users_names = { :athlete => :email }
# controller_guard is a block,
# if it returns true, the request will continue,
# else the request will be refused and returns "Permission Denied"
# if you switch from "admin" to user, the current_user param is "admin"
config.controller_guard = lambda { |current_user, request, original_user|
current_user.school_admin?
}
# view_guard is a block,
# if it returns true, the switch user select box will be shown,
# else the select box will not be shown
# if you switch from admin to "user", the current_user param is "user"
config.view_guard = lambda { |current_user, request, original_user|
current_user && current_user.school_admin?
}
# redirect_path is a block, it returns which page will be redirected
# after switching a user.
config.redirect_path = lambda { |request, params| '/' }
# helper_with_guest is a boolean value, if it set to false
# the guest item in the helper won't be shown
config.helper_with_guest = false
# false = login from one scope to another and you are logged in only in both scopes
# true = you are logged only into one scope at a time
config.login_exclusive = true
# switch_back allows you to switch back to a previously selected user. See
# README for more details.
config.switch_back = true
end
When the redirect happens, the user is taken to the root_url ("/") which then a filter runs to set the path in which the user is redirected to... when the admin tries to login as another user, the admin is redirected right back to their dashboard instead of being logged into the users dashboard. The user last_signed_in_at
attribute is set when the admin tries to login, but like I said, the admin actually doesn't go to the users' dashboard.
Also, what does it look like to log back in as an admin? I know how the config is setup, but what does it look like on the front-end?
I have changed my config in an initializer to be
config.controller_guard == lambda { |current_user, request| Rails.env.development? || (Rails.env.production? && current_user && current_user.admin?) }
However in production switch_user always fails. Even if I change the lambda to always return true it still fails. It seems that the config is not being read. However I know the switch_user initializer is working since changing config.provider to :authlogic causes an error since I am using devise.
http://switch-user-example.herokuapp.com/
=>
"Application Error"
:-(
before releasing:
Is there a simple way to detect that I have switched to a user and display a switch_back link? I tried to check for original_user
in the view, but it doesn't work this way.
I'd like to use chosen jquery plugin to be able to search inside select box, but didn't find the way to pass css class.
I have my app running in Test mode on Heroku. switch_user works well locally with Test mode but causes an exception on Heroku so that the app cannot start
I add config/initializers/switch_user.rb with these changes (to run in Test mode):
27 config.controller_guard = lambda { |current_user, request| Rails.env.development? || Rails.env.test? }
28
29 # view_guard is a block,
30 # if it returns true, the switch user select box will be shown,
31 # else the select box will not be shown
32 # if you switch from admin to "user", the current_user param is "user"
33 config.view_guard = lambda { |current_user, request| Rails.env.development? || Rails.env.test? }
And this is the error message on Heroku logs:
2011-09-21T02:32:27+00:00 app[web.1]: /app/config/initializers/switch_user.rb:1:in `<top (required)>': uninitialized constant SwitchUser (NameError)
2011-09-21T02:32:27+00:00 app[web.1]: from /app/.bundle/gems/ruby/1.9.1/gems/railties-3.0.10/lib/rails/engine.rb:201:in `block (2 levels) in <class:Engine>'
2011-09-21T02:32:27+00:00 app[web.1]: from /app/.bundle/gems/ruby/1.9.1/gems/railties-3.0.10/lib/rails/engine.rb:200:in `each'
2011-09-21T02:32:27+00:00 app[web.1]: from /app/.bundle/gems/ruby/1.9.1/gems/railties-3.0.10/lib/rails/engine.rb:200:in `block in <class:Engine>'
2011-09-21T02:32:27+00:00 app[web.1]: from /app/.bundle/gems/ruby/1.9.1/gems/railties-3.0.10/lib/rails/initializable.rb:25:in `instance_exec'
2011-09-21T02:32:27+00:00 app[web.1]: from /app/.bundle/gems/ruby/1.9.1/gems/railties-3.0.10/lib/rails/initializable.rb:25:in `run'
2011-09-21T02:32:27+00:00 app[web.1]: from /app/.bundle/gems/ruby/1.9.1/gems/railties-3.0.10/lib/rails/initializable.rb:50:in `block in run_initializers'
2011-09-21T02:32:27+00:00 app[web.1]: from /app/.bundle/gems/ruby/1.9.1/gems/railties-3.0.10/lib/rails/initializable.rb:49:in `each'
2011-09-21T02:32:27+00:00 app[web.1]: from /app/.bundle/gems/ruby/1.9.1/gems/railties-3.0.10/lib/rails/initializable.rb:49:in `run_initializers'
2011-09-21T02:32:27+00:00 app[web.1]: from /app/.bundle/gems/ruby/1.9.1/gems/railties-3.0.10/lib/rails/application.rb:134:in `initialize!'
2011-09-21T02:32:27+00:00 app[web.1]: from /app/.bundle/gems/ruby/1.9.1/gems/railties-3.0.10/lib/rails/application.rb:77:in `method_missing'
2011-09-21T02:32:27+00:00 app[web.1]: from /app/config/environment.rb:5:in `<top (required)>'
2011-09-21T02:32:27+00:00 app[web.1]: from <internal:lib/rubygems/custom_require>:29:in `require'
2011-09-21T02:32:27+00:00 app[web.1]: from <internal:lib/rubygems/custom_require>:29:in `require'
2011-09-21T02:32:27+00:00 app[web.1]: from config.ru:3:in `block (3 levels) in <main>'
Devise stores three things in the session to identify and authenticate a record: scope, the record's db id, and the record's "authenticatable_salt" (a method defined by devise)
The "switch back" / original_user functionality should probably do the same thing (at least if the provider is Devise), to be consistent from a security standpoint.
If sessions are being stored securely (encrypted), then this isn't strictly necessary for security, but again, it's more about being consistent with the provider's approach.
The issue -- and the reason Devise does this, I believe -- is that if sessions aren't being stored securely -- which is a setting outside the scope of this gem -- then all an attacker would need to do is inject an easily-guessable value, e.g. "admin_1", for the "original_user_scope_identifier" key into a session. Luckily, Rails now defaults to encrypted session cookies so it's probably not a major concern.
How to enable and disable the feature as well as describing how to construct a guard safely needs to be documented.
edit: marking for 0.9.3. I'd prefer to soft-launch the feature to give me a change to make any adjustments.
Got this error while switching user on Rails4 beta1
RuntimeError at /switch_user
Circular dependency detected while autoloading constant SwitchUserController
load_missing_constant(gem) activesupport-4.0.0.beta1/lib/active_support/dependencies.rb:460
455 if file_path
456 expanded = File.expand_path(file_path)
457 expanded.sub!(/\.rb\z/, '')
458
459 if loaded.include?(expanded)
460 raise "Circular dependency detected while autoloading constant #{qualified_name}"
461 else
462 require_or_load(expanded)
463 raise LoadError, "Unable to autoload constant #{qualified_name}, expected #{file_path} to define it" unless from_mod.const_defined?(const_name, false)
464 return from_mod.const_get(const_name)
465 end
I noticed that there's quite a bit of duplication between each of the provider methods. I was thinking about creating an abstract provider class and adding a subclass for each of the existing providers. This would remove the duplication and make it easier for other people to extend. SwitchUserController would then just delegate to the object based on the appropriate class.
What do you think ?
I'd also like some input on naming and structure.
/lib/providers/base
/lib/providers/devise
..etc...
Hi @andrewsprinz could you please post a stack trace and also tell me which version or sha or switch_user your tracking ?
Everything works in dev, but when I deploy to Heroku, the select box doesn't show when logged in as admin. I am using rails 3.2.13, devise 3.0.3, cancan 1.6.10 and rolify 3.2.0. The switch_user gem is loaded and shows up in heroku and the admin account is identical to my admin account in development.
Any ideas?
In new version config.controller_guard's lambda can use up to 4 arguments, but template contains only 2.
I need the controller, and spent 3 hours to found it.
In app/helpers/switch_user_helper.rb, it looks like "selected_user" was recently changed to be always nil. If you search for "selected_user" on the repo, you'll find:
def switch_user_select
return unless available?
options = []
selected_user = nil
users = SwitchUser::UserSet.users
...
:options => users,
:current_scope => selected_user
}
end
private
def user_tag_value(user, id_name, scope)
The result is that the first user is always selected. It makes it kind of hard to select the first user in the list, and I sort my list by most recently active user first, which ensures that I have a problem. I think this was a regression vs 0.9.3.
Thanks for the handy gem.
I may totally be missing something, but I could not come up with a solution to my problem short of changing the source code. I'm using two Devise models, neither one called User. When I include the switch_user_select, it throws an error saying that there is no method current_user, which is correct. I could fix the issue by changing switch_user_helper#6 to:
options += content_tag(:option, "Guest", :value => "", :selected => !provider.current_user(:my_default_user)
And switch_user_controller.rb#22:
SwitchUser.controller_guard(provider.current_user(:my_default_user, request)
But I'm sure I'm going about this completely the wrong way. If you could help me out, I would really be grateful, because I really don't want to miss out on this plugin!
Is it possible to configure this to not update devise trackable attributes such as current_sign_in_at, etc? Also asked here: http://stackoverflow.com/questions/23379570/devise-switch-user-how-to-avoid-trackable-update-for-a-switch-user
This works for me:
When i use this gem with twitter-bootstrap-rails
In app/helpers/switch_user_helper.rb:18
Rails call mthod: https://github.com/seyhunak/twitter-bootstrap-rails/blob/master/app/helpers/badge_label_helper.rb#L6 instead tag_label in helper file of gem.
right now if someone wants to manually test if the view is available, they'll need to use this incantation:
SwitchUser.guard_class.new(controller, provider).view_available?
That way too much implementation for them to need to know. Make methods like: switch_user_controller_available? and switch_user_view_available?.
After installing the gem and adding the switch_user_select call to my layout template I get the following error:
wrong number of arguments (2 for 0)
Layout source:
90: - if !Rails.env.production?
91: %small / #{link_to "Admin area", admin_root_path}
92: = switch_user_select
93:
94: %script(src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js")
Trace:
switch_user (0.5.0) lib/switch_user.rb:30:in `block in <module:SwitchUser>'
switch_user (0.5.0) app/helpers/switch_user_helper.rb:33:in `call'
switch_user (0.5.0) app/helpers/switch_user_helper.rb:33:in `available?'
switch_user (0.5.0) app/helpers/switch_user_helper.rb:3:in `switch_user_select'
app/views/layouts/application.html.haml:92:in `_app_views_layouts_application_html_haml___579286700033541313_2192473080_1977928861036260016'
This is with Rails 3.0.1 on Ruby MRI 1.9.2
Hi,
I installed the gem and get the following error when switching user: The action 'index' could not be found for SwitchUserController.
It seems the helper is making the http call to /switch_user, and this route is not added by the gem.
I'm on rails 3.1.
Thanks,
TF
Hello,
I'm having extreme difficulties with trying to figure out how it would be possible to know from a User model if current user was overriden / switched ?
I need to overload a method from Devise confirmable functionality to skip checking if user is confirmed.
Does switch_user adds any indicators to the model instance or does anyone know of any way how I could check that?
Thanks for help
Hello,
We get the following error when trying to use the gem:
=> Booting WEBrick
=> Rails 2.3.10 application starting on http://0.0.0.0:3000
/Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/activesupport-2.3.10/lib/active_support/dependencies.rb:182:in `require': no such file to load -- rails (MissingSourceFile)
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/activesupport-2.3.10/lib/active_support/dependencies.rb:182:in `require'
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/activesupport-2.3.10/lib/active_support/dependencies.rb:547:in `new_constants_in'
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/activesupport-2.3.10/lib/active_support/dependencies.rb:182:in `require'
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/switch_user-0.4.0/lib/switch_user.rb:1
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/bundler-1.0.2/lib/bundler/runtime.rb:64:in `require'
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/bundler-1.0.2/lib/bundler/runtime.rb:64:in `require'
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/bundler-1.0.2/lib/bundler/runtime.rb:62:in `each'
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/bundler-1.0.2/lib/bundler/runtime.rb:62:in `require'
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/bundler-1.0.2/lib/bundler/runtime.rb:51:in `each'
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/bundler-1.0.2/lib/bundler/runtime.rb:51:in `require'
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/bundler-1.0.2/lib/bundler.rb:112:in `require'
from /Users/khelal/Sites/monaqasat.com/2.0/config/boot.rb:42:in `load_gems'
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/rails-2.3.10/lib/initializer.rb:164:in `process'
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/rails-2.3.10/lib/initializer.rb:113:in `send'
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/rails-2.3.10/lib/initializer.rb:113:in `run'
from /Users/khelal/Sites/monaqasat.com/2.0/config/environment.rb:9
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/activesupport-2.3.10/lib/active_support/dependencies.rb:182:in `require'
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/activesupport-2.3.10/lib/active_support/dependencies.rb:182:in `require'
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/activesupport-2.3.10/lib/active_support/dependencies.rb:547:in `new_constants_in'
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/activesupport-2.3.10/lib/active_support/dependencies.rb:182:in `require'
from /Users/khelal/.rvm/gems/ree-1.8.7-2010.02@monaqasat/gems/rails-2.3.10/lib/commands/server.rb:84
from script/server:3:in `require'
from script/server:3
Is the gem only for Rails 3+ ?
I have FormUser Model which belongs to User model, and in my FormUser model is to tak care of omniauth schemes login with email password logins. When I try to use the switch back feature, the following error apepars.
SwitchUser::InvalidScope in SwitchUserController#remember_user
form_user is invalid and is not listed in SwitchUser#available_users
My form user model is as below.
class FormUser < User
attr_accessor :current_password
validates_presence_of :email, if: :email_required?
validates_uniqueness_of :email, allow_blank: true, if: :email_changed?
validates_format_of :email, with: Devise.email_regexp, allow_blank: true, if: :email_changed?
validates_presence_of :password, if: :password_required?
validates_confirmation_of :password, if: :password_required?
validates_length_of :password, within: Devise.password_length, allow_blank: true
def password_required?
return false if email.blank?
!persisted? || !password.nil? || !password_confirmation.nil?
end
def email_required?
true
end
end
I like using switch_user gem and I have configure it under development group in Gemfile, which I think should be by default. Same as the setting of https://github.com/flyerhzm/bullet.
Here's some settings in my app:
gem 'switch_user', group: 'development'
get 'switch_user' => 'switch_user#set_current_user' if Rails.env == 'development'
config.after_initialize do
SwitchUser.setup do |config|
# available_users is a hash,
# key is the model name of user (:user, :admin, or any name you use),
# value is a block that return the users that can be switched.
config.available_users = { :user => lambda { User.all.limit 5 } }
end
end
<%= switch_user_select if Rails.env == 'development' %>
currently parsing a scope_identifier of 'xx_admin_1' with /^([^_]+)_(.*)$/ results in match capture of $1->xx $2-> admin_1 and of course prevents switching to xx_admin
a simple change to the regular_expression in devise_handler would allow scope_containing a '_'.
use /^([^_].*)(.)$/ instead of /^([^_]+)(.)$/
this will allow handling scope names containing '_' and now match capture is $1-> xx_admin, $2-> 1
not sure if you have to fix but it would much appreciated
Thanks,
Victor
Hi, I had implemented the gem and it works. Though had to fuddle around a bit coz the app has various subdomains.
But after that I couldn't find any hint or text either in README/code/issues on how to switch back to admin or still showing the select box to switch to another user?
Is it intended to not allow this functionality or any hint/hack to implement such functionality?
Hi,
Thanks for the gem, it's been super useful.
I started having this issue when I updated to 1.0. I'm on Rails 4.2.2, Ruby 2.2.1, Devise 3.5.1. It won't load the switch_user_select.
Thanks!
ale
Completed 500 Internal Server Error in 127ms (ActiveRecord: 0.0ms)
SwitchUser::GuestDataSource:0x007fd8d426f138>
NoMethodError - undefined method all' for #<SwitchUser::GuestDataSource:0x007fd8d426f138>: switch_user (1.0.0) lib/switch_user/data_source.rb:10:in
block in all'
switch_user (1.0.0) lib/switch_user/data_source.rb:10:in each' switch_user (1.0.0) lib/switch_user/data_source.rb:10:in
flat_map'
switch_user (1.0.0) lib/switch_user/data_source.rb:10:in all' switch_user (1.0.0) lib/switch_user.rb:41:in
all_users'
switch_user (1.0.0) app/helpers/switch_user_helper.rb:14:in switch_user_select' app/views/layouts/one-page.html.erb:29:in
_app_views_layouts_one_page_html_erb___3458226017543812090_70284626163620'
actionview (4.2.2) lib/action_view/template.rb:145:in block in render' activesupport (4.2.2) lib/active_support/notifications.rb:166:in
instrument'
actionview (4.2.2) lib/action_view/template.rb:333:in instrument' actionview (4.2.2) lib/action_view/template.rb:143:in
render'
actionview (4.2.2) lib/action_view/renderer/template_renderer.rb:66:in render_with_layout' actionview (4.2.2) lib/action_view/renderer/template_renderer.rb:52:in
render_template'
actionview (4.2.2) lib/action_view/renderer/template_renderer.rb:14:in render' actionview (4.2.2) lib/action_view/renderer/renderer.rb:42:in
render_template'
actionview (4.2.2) lib/action_view/renderer/renderer.rb:23:in render' actionview (4.2.2) lib/action_view/rendering.rb:100:in
_render_template'
actionpack (4.2.2) lib/action_controller/metal/streaming.rb:217:in _render_template' actionview (4.2.2) lib/action_view/rendering.rb:83:in
render_to_body'
actionpack (4.2.2) lib/action_controller/metal/rendering.rb:32:in render_to_body' actionpack (4.2.2) lib/action_controller/metal/renderers.rb:37:in
render_to_body'
actionpack (4.2.2) lib/abstract_controller/rendering.rb:25:in render' actionpack (4.2.2) lib/action_controller/metal/rendering.rb:16:in
render'
actionpack (4.2.2) lib/action_controller/metal/instrumentation.rb:44:in block (2 levels) in render' activesupport (4.2.2) lib/active_support/core_ext/benchmark.rb:12:in
block in ms'
/Users/alexandrethome/.rvm/rubies/ruby-2.2.1/lib/ruby/2.2.0/benchmark.rb:303:in realtime' activesupport (4.2.2) lib/active_support/core_ext/benchmark.rb:12:in
ms'
actionpack (4.2.2) lib/action_controller/metal/instrumentation.rb:44:in block in render' actionpack (4.2.2) lib/action_controller/metal/instrumentation.rb:87:in
cleanup_view_runtime'
activerecord (4.2.2) lib/active_record/railties/controller_runtime.rb:25:in cleanup_view_runtime' actionpack (4.2.2) lib/action_controller/metal/instrumentation.rb:43:in
render'
actionpack (4.2.2) lib/action_controller/metal/implicit_render.rb:10:in default_render' actionpack (4.2.2) lib/action_controller/metal/implicit_render.rb:5:in
send_action'
actionpack (4.2.2) lib/abstract_controller/base.rb:198:in process_action' actionpack (4.2.2) lib/action_controller/metal/rendering.rb:10:in
process_action'
actionpack (4.2.2) lib/abstract_controller/callbacks.rb:20:in block in process_action' activesupport (4.2.2) lib/active_support/callbacks.rb:117:in
call'
activesupport (4.2.2) lib/active_support/callbacks.rb:117:in call' activesupport (4.2.2) lib/active_support/callbacks.rb:555:in
block (2 levels) in compile'
activesupport (4.2.2) lib/active_support/callbacks.rb:505:in call' activesupport (4.2.2) lib/active_support/callbacks.rb:505:in
call'
activesupport (4.2.2) lib/active_support/callbacks.rb:498:in block (2 levels) in around' activesupport (4.2.2) lib/active_support/callbacks.rb:313:in
call'
activesupport (4.2.2) lib/active_support/callbacks.rb:313:in block (2 levels) in halting' browser-timezone-rails (0.0.8) lib/browser-timezone-rails.rb:14:in
set_time_zone'
activesupport (4.2.2) lib/active_support/callbacks.rb:432:in block in make_lambda' activesupport (4.2.2) lib/active_support/callbacks.rb:312:in
call'
activesupport (4.2.2) lib/active_support/callbacks.rb:312:in block in halting' activesupport (4.2.2) lib/active_support/callbacks.rb:497:in
call'
activesupport (4.2.2) lib/active_support/callbacks.rb:497:in block in around' activesupport (4.2.2) lib/active_support/callbacks.rb:505:in
call'
activesupport (4.2.2) lib/active_support/callbacks.rb:505:in call' activesupport (4.2.2) lib/active_support/callbacks.rb:92:in
_run_callbacks'
activesupport (4.2.2) lib/active_support/callbacks.rb:776:in _run_process_action_callbacks' activesupport (4.2.2) lib/active_support/callbacks.rb:81:in
run_callbacks'
actionpack (4.2.2) lib/abstract_controller/callbacks.rb:19:in process_action' actionpack (4.2.2) lib/action_controller/metal/rescue.rb:29:in
process_action'
actionpack (4.2.2) lib/action_controller/metal/instrumentation.rb:32:in block in process_action' activesupport (4.2.2) lib/active_support/notifications.rb:164:in
block in instrument'
activesupport (4.2.2) lib/active_support/notifications/instrumenter.rb:20:in instrument' activesupport (4.2.2) lib/active_support/notifications.rb:164:in
instrument'
actionpack (4.2.2) lib/action_controller/metal/instrumentation.rb:30:in process_action' actionpack (4.2.2) lib/action_controller/metal/params_wrapper.rb:250:in
process_action'
activerecord (4.2.2) lib/active_record/railties/controller_runtime.rb:18:in process_action' actionpack (4.2.2) lib/abstract_controller/base.rb:137:in
process'
actionview (4.2.2) lib/action_view/rendering.rb:30:in process' actionpack (4.2.2) lib/action_controller/metal.rb:196:in
dispatch'
actionpack (4.2.2) lib/action_controller/metal/rack_delegation.rb:13:in dispatch' actionpack (4.2.2) lib/action_controller/metal.rb:237:in
block in action'
actionpack (4.2.2) lib/action_dispatch/routing/route_set.rb:74:in call' actionpack (4.2.2) lib/action_dispatch/routing/route_set.rb:74:in
dispatch'
actionpack (4.2.2) lib/action_dispatch/routing/route_set.rb:43:in serve' actionpack (4.2.2) lib/action_dispatch/journey/router.rb:43:in
block in serve'
actionpack (4.2.2) lib/action_dispatch/journey/router.rb:30:in each' actionpack (4.2.2) lib/action_dispatch/journey/router.rb:30:in
serve'
actionpack (4.2.2) lib/action_dispatch/routing/route_set.rb:819:in call' bullet (4.14.7) lib/bullet/rack.rb:12:in
call'
warden (1.2.3) lib/warden/manager.rb:35:in block in call' warden (1.2.3) lib/warden/manager.rb:34:in
catch'
warden (1.2.3) lib/warden/manager.rb:34:in call' rack (1.6.4) lib/rack/etag.rb:24:in
call'
rack (1.6.4) lib/rack/conditionalget.rb:25:in call' rack (1.6.4) lib/rack/head.rb:13:in
call'
actionpack (4.2.2) lib/action_dispatch/middleware/params_parser.rb:27:in call' actionpack (4.2.2) lib/action_dispatch/middleware/flash.rb:260:in
call'
rack (1.6.4) lib/rack/session/abstract/id.rb:225:in context' rack (1.6.4) lib/rack/session/abstract/id.rb:220:in
call'
actionpack (4.2.2) lib/action_dispatch/middleware/cookies.rb:560:in call' activerecord (4.2.2) lib/active_record/query_cache.rb:36:in
call'
activerecord (4.2.2) lib/active_record/connection_adapters/abstract/connection_pool.rb:649:in call' activerecord (4.2.2) lib/active_record/migration.rb:378:in
call'
actionpack (4.2.2) lib/action_dispatch/middleware/callbacks.rb:29:in block in call' activesupport (4.2.2) lib/active_support/callbacks.rb:88:in
call'
activesupport (4.2.2) lib/active_support/callbacks.rb:88:in _run_callbacks' activesupport (4.2.2) lib/active_support/callbacks.rb:776:in
_run_call_callbacks'
activesupport (4.2.2) lib/active_support/callbacks.rb:81:in run_callbacks' actionpack (4.2.2) lib/action_dispatch/middleware/callbacks.rb:27:in
call'
actionpack (4.2.2) lib/action_dispatch/middleware/reloader.rb:73:in call' actionpack (4.2.2) lib/action_dispatch/middleware/remote_ip.rb:78:in
call'
rollbar (1.5.3) lib/rollbar/middleware/rails/rollbar.rb:24:in block in call' rollbar (1.5.3) lib/rollbar.rb:799:in
scoped'
rollbar (1.5.3) lib/rollbar/middleware/rails/rollbar.rb:22:in call' better_errors (2.1.1) lib/better_errors/middleware.rb:84:in
protected_app_call'
better_errors (2.1.1) lib/better_errors/middleware.rb:79:in better_errors_call' better_errors (2.1.1) lib/better_errors/middleware.rb:57:in
call'
actionpack (4.2.2) lib/action_dispatch/middleware/debug_exceptions.rb:17:in call' rollbar (1.5.3) lib/rollbar/middleware/rails/show_exceptions.rb:22:in
call_with_rollbar'
actionpack (4.2.2) lib/action_dispatch/middleware/show_exceptions.rb:30:in call' railties (4.2.2) lib/rails/rack/logger.rb:38:in
call_app'
railties (4.2.2) lib/rails/rack/logger.rb:22:in call' quiet_assets (1.1.0) lib/quiet_assets.rb:27:in
call_with_quiet_assets'
request_store (1.1.0) lib/request_store/middleware.rb:8:in call' actionpack (4.2.2) lib/action_dispatch/middleware/request_id.rb:21:in
call'
rack (1.6.4) lib/rack/methodoverride.rb:22:in call' rack (1.6.4) lib/rack/runtime.rb:18:in
call'
activesupport (4.2.2) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in call' rack (1.6.4) lib/rack/lock.rb:17:in
call'
actionpack (4.2.2) lib/action_dispatch/middleware/static.rb:113:in call' rack (1.6.4) lib/rack/sendfile.rb:113:in
call'
railties (4.2.2) lib/rails/engine.rb:518:in call' railties (4.2.2) lib/rails/application.rb:164:in
call'
rack (1.6.4) lib/rack/content_length.rb:15:in call' thin (1.6.3) lib/thin/connection.rb:86:in
block in pre_process'
thin (1.6.3) lib/thin/connection.rb:84:in catch' thin (1.6.3) lib/thin/connection.rb:84:in
pre_process'
thin (1.6.3) lib/thin/connection.rb:53:in process' thin (1.6.3) lib/thin/connection.rb:39:in
receive_data'
eventmachine (1.0.7) lib/eventmachine.rb:187:in run_machine' eventmachine (1.0.7) lib/eventmachine.rb:187:in
run'
thin (1.6.3) lib/thin/backends/base.rb:73:in start' thin (1.6.3) lib/thin/server.rb:162:in
start'
rack (1.6.4) lib/rack/handler/thin.rb:19:in run' rack (1.6.4) lib/rack/server.rb:286:in
start'
railties (4.2.2) lib/rails/commands/server.rb:80:in start' railties (4.2.2) lib/rails/commands/commands_tasks.rb:80:in
block in server'
railties (4.2.2) lib/rails/commands/commands_tasks.rb:75:in tap' railties (4.2.2) lib/rails/commands/commands_tasks.rb:75:in
server'
railties (4.2.2) lib/rails/commands/commands_tasks.rb:39:in run_command!' railties (4.2.2) lib/rails/commands.rb:17:in
<top (required)>'
bin/rails:8:in require' bin/rails:8:in
after updating to switch_user 0.9.3(from 0.9.2) we started to see errors like this:
An ActionView::Template::Error occurred in users#index:
wrong number of arguments (2 for 0)
activesupport (3.2.13) lib/active_support/core_ext/module/attribute_accessors.rb:10:in `view_guard'
Hi
Thanks for the gem, it works really well for my Rails - devise setup. However I'm facing this issue where I have the user identifier other than ID:
config.available_users_identifiers = { :user => :slug }
When I check the checkbox next to switch_user_select before switching from "admin" to a "user" for switching back, the value stored in the session[:original_user_scope_identifier] is still "user_ID" instead of "user_SLUG". Consequently, I cannot "switch back" as the saved admin user cannot be found with the query:
User.where(slug: ID_stored_in_session)
If I find some time, I'd try to submit a pull request with a fix. Reporting it until then :)
The switch user as a select box using erb was working perfectly but we recently has too many users in our database so I edited the
<%= switch_user_select %>
with
<%= link_to user.login, "/switch_user?scope_identifier=user_#{user.id}" %>
and it started giving me
undefined local variable or method `user' for #<#Class:0x007fbc83c89258:0x007fbc83c880d8>
error
any idea on how to fix this or is it a gem thing?
Not sure what has changed since the previous version (can we get a ChangeLog?)
But now whenever our support staff tries to switch to a user, our app hangs. From a quick look it looks like all Users are trying to be loaded in memory. When you have 100s of thousands of Users that's not possible. Were there recent changes in this regard? Downgrading to 0.9.4 does fix the issue for us.
Thanks!
Hi,
Great Gem, thanks!
One small comment - I've been trying to use the "switch back" option and kept getting cookie overflow error. i checked the gem code and i believe i found the issue.
The code is trying to save the entire user object into the session -
def remember_current_user(remember)
if remember
@controller.session[:original_user] = current_user
else
@controller.session.delete(:original_user)
end
end
i'm using a very basic user model (devise gem, didn't add any additional members besides what devise supports) and it appears that after the enchryption the data becomes too big to store in cookie. The fix for me is very simple (overriding 2 methods from SwitchUser::Provider::Base) - just store the user id, and then in the original_user method reload it from DB
so something like:
def original_user
current_user.class.find(@controller.session[:original_user]) if current_user && @controller.session[:original_user]
end
def remember_current_user(remember)
if remember
@controller.session[:original_user] = current_user.id
else
@controller.session.delete(:original_user)
end
end
Just a thought (+ if someone else had this issue and was wondering)
when add gem 'switch_user' to gemfile, I met a 404 problem, caused by lib/switch_user/data_source.rb#33 "[email protected]".delete ":user_" ==> [email protected]
, then I find master branch fixed the problem, could you update rubygems version to help others?
I've got around 400,000 users and switch takes ages.
It also tries to load all of these users into memory.
Any ideas?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.