setting up gravitars for my posts through users - ruby-on-rails

I just set it up so that when a user signs up for my blog it gives them a gravatar in the users index. That works fine but I was thinking of making it so that when that user makes a post it will display their gravatar from the user. I just made a user_id colum to posts through a migration.
here is a copy of my schema
ActiveRecord::Schema.define(version: 20131114141804) do
create_table "comments", force: true do |t|
t.text "content"
t.datetime "created_at"
t.datetime "updated_at"
t.string "post_id"
end
create_table "posts", force: true do |t|
t.string "title"
t.text "content"
t.datetime "created_at"
t.datetime "updated_at"
t.string "user_id"
end
create_table "users", force: true do |t|
t.string "email"
t.string "password_digest"
t.datetime "created_at"
t.datetime "updated_at"
t.string "auth_token"
t.string "password_reset_token"
t.datetime "password_reset_sent_at"
t.string "avatar_url"
end
end
models:
user:
class User < ActiveRecord::Base
has_secure_password
validates_uniqueness_of :email
has_many :posts
validates_presence_of :password, :on => :create
before_create { generate_token(:auth_token) }
def send_password_reset
generate_token(:password_reset_token)
self.password_reset_sent_at = Time.zone.now
save!
UserMailer.password_reset(self).deliver
end
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
end
Post:
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
end
class Comment < ActiveRecord::Base
has_many :posts
end
application_helper.rb
module ApplicationHelper
def avatar_url(user)
gravatar_id = Digest::MD5::hexdigest(user.email).downcase
"http://gravatar.com/avatar/#{gravatar_id}.png?s=200"
end
end
was trying to do something new, could anyone help me out and or point me in the right direction?

I'd recommend taking a good look at using paperclip for the attachment process rather than trying to re-invent the wheel. Paperclip's documentation actually uses a user avatar as an example, so it'd be perfect for your use case.

You may want to use a Rails plugin to integrate with Gravatar rather than doing it yourself:
gravtastic
Gravatar Rails plugin

Related

has_one association not adding methods to belongs_to class

I have two tables User and UserToken. User has_one: token and UserToken belongs_to :user. I was under the impression this would add UserToken#User method to the UserToken class. However, I am getting:
undefined method 'user' for '#' with the
following 'UserToken.where(user_id: 1).user
Do I not understand the association correctly or have I not set it up right?
UsersController:
def get
user = UserToken.where(user_id: 1).user
render json: user.to_json
end
User Model:
class User < ApplicationRecord
has_one :user_token
end
UserToken Model:
class UserToken < ApplicationRecord
belongs_to :user
end
Migration:
def change
create_table :users do |t|
# This id comes from Auth0
t.datetime :date
t.timestamp :updated_at
t.timestamp :created_at
end
create_table :user_tokens do |t|
t.belongs_to :user
# This comes from plaid when a user signs in
t.string :token
t.timestamp :updated_at
t.timestamp :created_at
end
end
Schema:
ActiveRecord::Schema.define(version: 2019_09_19_004350) do
create_table "user_tokens", force: :cascade do |t|
t.bigint "user_id"
t.string "token"
t.datetime "updated_at"
t.datetime "created_at"
t.index ["user_id"], name: "index_user_tokens_on_user_id"
end
create_table "users", force: :cascade do |t|
t.datetime "date"
t.datetime "updated_at"
t.datetime "created_at"
end
end
What you want is:
UserToken.where(user_id: 1).first.user
or better yet:
UserToken.find_by(user_id: 1).user
You're getting the "undefined method" error because #where returns an ActiveRecord::Relation and an ActiveRecord Relation has no #user method.
UserToken.where(user_id: 1).class.name
#=> "ActiveRecord::Relation"
UserToken.where(user_id: 1).first.class.name
#=> "UserToken"

How to add relation to existing object in Rails

I want to add relation between existing post and author.
I was trying to modify created_by attribute but it's not accessible from object.
def set_author
if (#post.created_by.empty? && #post.author_code.present?)
if #post.author_code == params[:author_code]
#post.created_by = current_user
else
raise(ExceptionHandler::InvalidAuthorCode, Message.invalid_author_code)
end
else
raise(ExceptionHandler::DisallowedAction, Message.action_not_allowed)
end
end
It's not working because there is no method #post.created_by even if it's present db.
Post model from schema.rb
create_table "posts", force: :cascade do |t|
t.string "title"
t.text "content"
t.boolean "accepted", default: false
t.string "created_by"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "author_code"
end
Edit:
part of post.rb
belongs_to :user, optional: true, foreign_key: :created_by
part of user.rb
has_many :confessions, foreign_key: :created_by
Assuming that it only fails for the #post which don't have any created_by OR user then you can use following:
#post.try(:created_by).blank? && #post.author_code.present?
I was trying to update #post attributes a wrong way. Changed
#post.created_by = current_user
to
#post.update_attribute(:created_by, current_user)
and it's working.
It's not a Devise user model, just self written.

Ruby on Rails - Scoping resources by current_account

I’m new to ruby on rails and I’m a bit stuck with what the best next step is in a multi-tenancy application I’m building.
Basically I want to scope resources by account_id, so I have created a method and helper called current_account in my accounts base_controller.
However, the tutorial I’m following scopes current_account by subdomain which I do not want to do. So I need a way to identify the current user’s account_id so that that I can have a resource variable #contact = current_account.contacts."all".
Do I need to make a new association between the user and account model so that I can use the current_user helper to define the current account id or is there a better way? If so, what is the best way to do this?
Background
The first user who signs up becomes the account owner. Account owners can then invite other users to the account. I'm using the devise gem. Resources are scoped by account so that only users linked to an account can see the records belonging to that account.
Base Controller
module Accounts
class BaseController < ApplicationController
def current_account
#current_account ||= ?????
end
helper_method :current_account
def owner?
current_account.owner == current_user
end
helper_method :owner?
end
end
Contacts (my resource) Controller
module Accounts
class ContactsController < Accounts::BaseController
def index
#contact = current_account.contacts.all
end
end
end
Account Model
class Account < ActiveRecord::Base
belongs_to :owner, class_name: "User"
accepts_nested_attributes_for :owner
validates :subdomain, presence: true, uniqueness: true
has_many :contacts
has_many :invitations
has_many :memberships
has_many :users, through: :memberships
end
Invitation Model
class Invitation < ActiveRecord::Base
belongs_to :account
validates :email, presence: true
end
Membership Model
class Membership < ActiveRecord::Base
belongs_to :account
belongs_to :user
end
User Model
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Routes
Rails.application.routes.draw do
devise_for :users
scope module: "accounts" do
resources 'dashboard'
resources 'contacts'
resources :invitations, only: [:new, :create] do
member do
get :accept
patch :accepted
end
end
resources :users, only: [:index, :destroy]
end
Schema
ActiveRecord::Schema.define(version: 20170124002015) do
create_table "accounts", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "owner_id"
t.string "subdomain"
end
add_index "accounts", ["subdomain"], name: "index_accounts_on_subdomain"
create_table "contacts", force: true do |t|
t.string "first_name"
t.string "last_name"
t.string "phone"
t.string "email"
t.text "comments"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "account_id"
end
add_index "contacts", ["account_id"], name: "index_contacts_on_account_id"
create_table "invitations", force: true do |t|
t.string "email"
t.integer "account_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "token"
end
add_index "invitations", ["account_id"], name: "index_invitations_on_account_id"
add_index "invitations", ["token"], name: "index_invitations_on_token"
create_table "memberships", force: true do |t|
t.integer "account_id"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "memberships", ["account_id"], name: "index_memberships_on_account_id"
add_index "memberships", ["user_id"], name: "index_memberships_on_user_id"
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
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"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
There are two possible associations between users and accounts:
users have many accounts
users belong to an account
In the first case, the tenant cannot be set from the current_user, because it's unclear which account should be used as the current tenant. The membership table in the schema.rb indicates this is the approach taken by the tutorial you mentioned. Loading the account by subdomain helps specify which account shall be used as the current tenant.
In the second case, every user has just one account. Users get an account_id, the membership table becomes obsolete, and you can load the current tenant like so:
def current_account
#current_account ||= current_user.account
end
Do I need to make a new association between the user and account model
so that I can use the current_user helper to define the current
account id or is there a better way? If so, what is the best way to do
this?
It seems to me that you want to take the second approach, which requires that an account has_many users and a user belongs_to an account.

Which relationship is good to use STI or Polymorphism?

I have read about them but still not clear to me which one I suppose to use and how.
I have User model, Message model and Place model
Message model:
class Message < ActiveRecord::Base
belongs_to :user
end
Messages Table:
create_table "messages", force: true do |t|
t.string "title"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
User model:
class User < ActiveRecord::Base
has_many :messages
end
Users Table:
create_table "users", force: true do |t|
t.string "email"
t.string "password_digest"
t.datetime "created_at"
t.datetime "updated_at"
t.string "username"
end
Now, what I want to do is:
"USER" says "MESSAGES" from "PLACES"
eg. "AHMED" says "HELLO" from "EARTH"
For me both Models (Message and Place) have same data (data type) and same behaviours. So places table should be:
create_table "places", force: true do |t|
t.string "name"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
Now may be I'm confused or making big deal than it should be.
What kind of relation should Message and Place have? should it be STI or Polymorphism?
How should I decide?
I'd appreciate the thinking process of how and why I decide specific association.
This example, despite Messages and Places having the same data, doesn't seems a STI/Polymorphism scenario and they should have two different tables.
This could work as a solution:
create_table "users" do |t|
t.string "username"
end
create_table "messages" do |t|
t.string "text"
t.integer "user_id"
t.integer "place_id"
end
create_table "places" do |t|
t.string "name"
end
class User < ActiveRecord::Base
has_many :messages
has_many :places, through: :messages
end
class Place < ActiveRecord::Base
end
class Message < ActiveRecord::Base
belongs_to :user
belongs_to :place
def to_s
"#{user.username} says #{title} from #{place.name}"
end
end
ahmed = User.new(username: "AHMED")
earth = Place.new(name: "EARTH")
message = Message.new(text: "HELLO", user: ahmed, place: earth)
puts message
# => "AHMED says HELLO from EARTH"

Rails has_one and belongs_to help

I have two models: User and Store
class Store < ActiveRecord::Base
belongs_to :user
class User < ActiveRecord::Base
has_one :store
Schema looks like this:
create_table "users", :force => true do |t|
t.string "name"
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
t.string "encrypted_password"
t.string "salt"
t.boolean "admin", :default => false
t.string "username"
t.string "billing_id"
end
create_table "stores", :force => true do |t|
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
t.string "store_name"
t.integer "user_id"
end
User must login in order to sign up a store by inputting "email" and "store_name". create from stores_controller looks like this:
def create
#store = Store.new(params[:store])
if #store.save
#store.user_id = current_user.id
flash[:success] = "this store has been created"
redirect_to #store
else
#title = "store sign up"
render 'new'
end
end
In ApplicationsController
def current_user
#current_user ||= user_from_remember_token
end
However, when I check in the database, #store.user_id = nil. For some reason, it's not able to put in current_user.id into #store.user_id. Anybody able to help in detecting why this might be? I thought I had associations correctly implemented. Thanks
This is happening because you're setting the #store.user_id AFTER saving it.
Ideally, you should be using the association builder for this:
def new
#store = #current_user.store.build(params[:store])
More information about these can be found in the "Association Basics" guide.

Resources