how do you integration OmniAuth (Twitter) to an existing user model? - ruby-on-rails

I am using OmniAuth and I'm able to get the callback successfully working.
When I browse to /auth/twitter and log in using Twitter, it leads me back to /auth/twitter/callback with unformatted text that has user ID, profile image URL, screen name, etc.
I haven't done anything with this output yet and that's where I need help.
I already have an existing authentication system and I want to keep everything the way it is. I am looking to grab from Twitter just the screen name, their oauth_token, their oauth_token_secret and their email address (if possible) to create a new account on my site/login to my site. If I want to keep the exact same behavior of my current website and just want to allow people to login/register using Twitter, how can I do that?
Here's my already existing user table
create_table "users", :force => true do |t|
t.string "name"
t.string "email"
t.timestamp "created_at", :null => false
t.timestamp "updated_at", :null => false
t.string "password_digest"
t.string "remember_token"
Can I add the oauth_token and oauth_token_secret columns to this table and make it work that way?

You can. Check Ryans railscasts.com/episodes/241-simple-omniauth. Also be aware that twitter does not return email. You may also need to change user model to allow null for password etc, if you are planning to allow login either with twitter or with traditional user/pass (you may need to work on validation part if the user chose the later)

Related

Ruby on Rails 5 strong parameters

I'm having some troubles with a project I'm working on. Be warned I consider myself very much a beginner/novice at all this still :)
To keep things short and sweet, I'm using Rails & active admin to build up an admin interface where i can perform CRUD operations on my database models, which is all working great. However I recently decided I wanted to add another field to one of my models, a "description" field, so generated a migration, ran rake db:migrate and updated my list of allowed params in my controller & active admin resource.
My problem is data is not saved for this new "description" field - wether its via creating a new entry or updating an existing one. I can see the output in the terminal confirms it is being filtered out by strong params; returning Unpermitted parameter: :Description However i am under the impression i have set up my strong params correctly, so I'm unsure if i have set up my permit params properly or what else i can do.
Using Rails 5.1.0 & will post code below.
class CellsController < InheritedResources::Base
def index
end
private
def cell_params
params.require(:cell).permit(:name, :description)
end
end
#database schema for my cell model
create_table "cells", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "Description"
end
#Active Admin resource
ActiveAdmin.register Cell do
permit_params :name, :description
end
Again, greatly appreciate any help as I'm sure I've overlooked something, happy to provide any other information that is required :)
Thankyou!
To me it looks like the description param is not accepted because the model only has a Description column (with a capitalised D). To fix that, either change each params.permit(:description) to params.permit(:Description) or just rename the column inside a new migration:
def change
rename_column :cells, :Description, :description
end
I recommend renaming the column as it will avoid any trouble with the column in the future.

Activity stream in angular or rails?

I have rails/angular app where users can add movies to their watchlist, users can also create friendships with other users. Now I would like to create a activity stream that notifies users when a friend has added a movie to their watchlist. But I can't find any good resources on how to get started on this feature.
For the friendships I have a friendship model,
create_table "friendships", force: :cascade do |t|
t.integer "user_id"
t.integer "friend_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
What would be the connection between users, friends and newly added records (movies)?
You can try public_activity gem. I believe you find it usefull and the documentation provides almost every case you describe.
You have one screencast on the subject here and it supports both Rails 3.x and 4.x.
About your model, I believe you should start first by creating an relational model of your data and then translate it to Rails relationships.
You can try
Paper trail
Any time a change is made in your system, paper trail can track the user id via a whodunnit property. This is set automatically if your controller makes a current_user object available. . it will also track any user, regardless of whether there is an actual relationship between the user and the model.
https://github.com/pokonski/public_activity. It's pretty simple to install and setup.
Also there is Audited
PaperTrail, Vestal versions and Acts as versioned are all very powerful versioning gem. Yes, you can also use it to audit/track users' activities , but it's not very straight forward because they are 'versioning tools', but not for the 'auditing purpose'
Userstamp and audited are for auditing purposing only. but Userstamp is for older Rails versions ( it's a plugin... which is not supported by Rails3(or 3.1, 3.2?) anymore )

Identifying links in message body for view

I have a rails app where users can talk to each other via chat. If they send over links in the chat (if you send anything at the moment in the chat it gets saved as message.body) to each other I would like to somehow distinguish it from plain text to be able to show the links on an index page later. How could I do that? At the moment 2 users have one common conversation. And messages belong to conversation.
Should I try to save them as different message attribute like message.link? If yes, then how can I distinguish message.link from message.body when creating the message. Or can I just simply use some helper method and showing only those message.body-s where the body itself is a link. And what if the half of the message is plain text and the other half is a link?
message schema
create_table "messages", force: :cascade do |t|
t.text "body"
t.integer "conversation_id"
t.integer "user_id"
t.string "message_attachment"
end
You can use Rinku.
1. Add it to your gemfile
gem 'rinku'
2. Create a method in your ApplicationHelper name it find_links
def find_links(message_body)
Rinku.auto_link(message_body, mode=:all, link_attr=nil, skip_tags=nil).html_safe
end
3. In your view pass the message body to the find_links method.
= find_links(message.body)

Subscription based restrictions for rails queries

I have a rather complex issue that I could some assistance with, as all implementations I've been trying are flawed (Rails 4.2.1).
Users have access to devices:
create_table "devices", force: :cascade do |t|
t.string "device_guid"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_ids"
end
and devices have many data entries:
create_table "datas", force: :cascade do |t|
t.string "device_id"
t.datetime "start_time"
t.datetime "end_time"
end
We want to restrict all queries to the data based on Subscriptions.
create_table "subscriptions", force: :cascade do |t|
t.integer "device_id"
t.integer "user_id"
t.datetime "start_date"
t.datetime "end_date"
end
So effectively, data should not be accessed unless Subscriptions allows it.
I wanted to have this restriction done in one place (not by individual method to access it), so other people writing code still deal with the subscription restriction. I don't want to use a 3rd party gem as the data is very sensitive.
I thought the most obvious way to do this would be set a default_scope on the Data model, but I ran into several problems:
1) You can't access #user from the Data model. I got around this with an ugly hack to access User.current from the model.
2) I can't use current_user since we have admins that pose as other users, and need to see the data as they would. Used the same workaround as #1
3) There can be multiple subscriptions with different dates for the same user and device. There isn't any way to do an ActiveRecord Query that I know of that can account for two separate date ranges (I got around this by using arel_table).
4) This makes all of the methods written that query the data to fail when I'm in the rails console (and theoretically through an API interface). I got around this by ignoring the default scope if there is no User.current, but obviously that's a security concern.
This is my current implementation (in psuedocode):
query = []
Subscription.each do |s|
if (User.current.id == s.user_id)
temp = Data.all.where(data[:start_time] >= s.start_date).where(data[:end_time] <= s.end_date).where(data[:device_id] == Device.find_by(id: s.device_id).device_guid)
end
end
query += temp
end
default_scope { query }
I put this code just directly into the model. I didn't think it would work, but it does... sometimes. It acts oddly, sometimes completely restricting a user when it shouldn't, although it hasn't (yet) given somebody access to data they should not have.
I'm looking to redesign this from the ground up, and do it the best way. I'm open to any suggestions (except 3rd-party, sorry) on how best to approach it. I don't mind if it takes a lot of work to implement, I'd rather do it right this time. Any account for expandability (such as if we implemented an API for remote queries) would be a great feature as well, though we don't currently need it.
Just to reiterate, I insist that this restriction be "automatic" to all queries, so that if a front coder for instance writes:
<%= #user.device.find(1).data.all.count %>
in a view, it won't show any data the user doesn't have a subscription for.
Thanks for any suggestions. Sorry for the long wall of text, this has been a rather perplexing problem.

Trying to rename Devise Model name in ruby on rails

We had 2 ruby on rails apps that one was using json outputs from the other. But we decided to integrate them which ran into a lot of issues.
The issue now is, the writer of one system used to 'devise' gem for all user authentication and registration, which was fine. But when we had to integrate them it caused problems, because the other system also had a model named users, which was not used for this purpose.
And it would be A LOT easier to just rename the devise user model to something like "site-user" which im currently trying.
Than re-name the other model.
I tried renaming everything that relates to devise in all the files to siteuser instead of user but still getting errors. Anyone have any advice on this. If i can just get this devise user to use a different model name than "User" i will be able to make a lot of progress but this is proving quite the annoyance.
Current error is
NoMethodError in Devise::Sessions#new - highlighting the line with "if user_signed_in"
<li>
<%= link_to t('nav.support'), 'http://banana.sweatervest.net/' %>
</li>
<%- if user_signed_in? -%>
<%- if controller_name != 'dashboard' -%>
<li>
<%= link_to t('nav.dashboard'), :dashboard %>
Why not uninstall it and then reinstall the model.
First:
rails destroy devise User
then:
rails generate devise whateveryourmodelnamehere
Much easier than trying to rename everything, only because I've been there ;)
I actually took the long route (? 1 hour work) to rename my Devise model I had named Admin some decade ago. I wanted it to be User.
(Previous rails version 4, into my latest rails version 7, devise 4.7)
Note that you might have got yourself wrapped a lot more into the naming than I did so buyers of this solution beware! For instance I had not indexes on any of my tables (which I will do now for goodness sake). Devise itself doesn't really write the model name into stuff so it's mostly digging into your own past.
My step by step that worked for me:
I - start a new clean git branch. You will suffer unless you are able to oversee what you are doing next.
II - Renaming all cases of admin -> user. (~34 files affected)
Using search/replace (case sensitive) in my editor:
lowcases of admin -> user (also look for admins -> users that got missed)
uppercase Admin -> User
Manually rename some files like the model: admin.rb -> user.rb
III - Create some migrations to create new users table and change admin_id to user_id in those tables affected:
Take the create_table body from schema.rb and wrap that into a migration, using the new name of the devise model, mine ended up like:
class AddUsersTable < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string "email", limit: 255, default: "", null: false
t.string "encrypted_password", limit: 255, default: "", null: false
t.string "reset_password_token", limit: 255
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip", limit: 255
t.string "last_sign_in_ip", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
end
end
And next a migration to change what other tables need to update the foregin key
class RenameAdminIdsToUser < ActiveRecord::Migration[5.2]
def change
rename_column(:batches, :admin_id, :user_id)
rename_column(:offices, :admin_id, :user_id)
end
end
IV - copy data from old table to the new.
In my case I'm using postgres, but the SQL will probably work with most SQL-based DBs. Here I logged into my postgres-db and run the following sql:
INSERT INTO users (SELECT * FROM admins);
(This query can also be put in a migration which is a bit cleaner.)
V - if you are setting up a new rails like me - going from rails 5 to 7, also make sure to copy settings from devise.rb, like pepper token keys to match the data you have in your old table.
After these steps my rails app was moving on with User instead of Admin as if nothing happened!

Resources