jeudi 15 juin 2017

Ruby on Rails - Security Notifications

I'm working on a project with ROR framework and the gem "Devise" for the authentication.

Actually i have 3 model of users :

  • User
  • Admin
  • Company

I would like to know if there is a way to get the user's account activities with the time and ip (i got it with devise):

When the user login, logout, fail login, change password, unlock account etc ...

Shall i build a new model : security_notifications which is associated with User model, and override devise Controllers to create the notification after every actions ? Or there is a better method ?

Thanks,

Put gem class into namespace

To my Rails Gemfile I added a new Gem. It get's used like this:

Email::Client

The issue i'm having right now is that I also have a class in my Rails-App that's called Email. Now sometimes when I try to initialize it I get the following error:

Email.new # >> undefined method 'new' for Email:Module

Probably because Email is a Module in the Gem. How can fix this issue? Is there a way to namespace the Gem Module? I don't want to rename the Email-Class.

mercredi 14 juin 2017

rails cannot create a new item

I am working on creating a small rails app, and I have ran into a problem that I believe is in the backend of my database, but I don't know how to solve it. Ultimately what is happening is if I try to go to my my new url, I get an error stating PG::UndefinedTable: ERROR: relation "caves" does not exist LINE 8: WHERE a.attrelid = '"caves"'::regclass

All I am trying to do us create a new cafe I go to localhost:3000/cafes/new but for some really annoying reason, caves somehow somewhere got in the mix and I don't know how to get around this.

My controller is essentially below. (the rest of the items in my controller are empty methods at this point)

  def new
    @cafe = Cafe.new
  end

  def create
    @cafe = Cafe.new(cafe_params)
  end

  private

  def cafe_params
    params.require(:name, :description)
  end

My schema table is

  enable_extension "plpgsql"

  create_table "cafes", force: :cascade do |t|
    t.string "name"
    t.text "description"
  end

  create_table "users", force: :cascade do |t|
    t.string "first_name"
    t.string "last_name"
    t.string "email"
    t.integer "age"
  end

I have two empty models right now one called user.rb and the other cafe.rb

This is where I get really confused because there is no cave relation in my model.

class Cafe < ApplicationRecord
end

Thats about where I am. Would anyone know what I could do with this? I'm thinking that possibly there is a duplicate database somewhere and it needs to be destroyed. I've tried a rake db:drop + rake db:create + rake db:migrate route with what I have, but no luck. I know there is a way to open up my database through straight up psql, and I think that may be the way into really truly debugging this problem. (i've seen it done once, but don't remember how to do it, let alone only know active record, not sql)

Does anyone know whats going on here? Or does anyone know how to get into psql and how to find something like this?

I really do appreciate it.

Passing a default parameter to a Rails 3 route makes it fail to match the route in the controller test

I'm upgrading an old application for a non-profit, and I've having issues with some routes and controller tests on Rails 3.0.20 (Rails 2 -> 3 is the first of many upgrades I need to make :( )

This is my route definition:

match "new/tribes" => "news#tribes",
  as: "en_news_tribes",  
  defaults: {
    page_slug: 'tribes',
    language_id: 3,
    section_id: 4
  }

The idea is that when the controller is called the parameters will include the default values for page_slug, language_id and section_id

In my controller test (TestUnit based) the action is invoked like this:

get :tribes, { section_id: 4, language_id: 4, tribe_id: @loc_tribe.tribe.id }

But this produces this routing exception:

ActionController::RoutingError: No route matches {:section_id=>4, :language_id=>3, :tribe_id=>1, :controller=>"news", :action=>"tribes"}

Only if I specify all the default parameters does it find a route (and the test passes):

get :tribes, { section_id: 4, language_id: 4, tribe_id: @loc_tribe.tribe.id, page_slug: 'tribes' }

If the parameters I pass don't match the default parameter values specified in config/routes.rb it doesn't find the route.

i.e. This doesn't work:

get :tribes, { section_id: 4, language_id: 4, tribe_id: @loc_tribe.tribe.id, page_slug: 'Abc123' }

So it seems like these default values are in fact behaving as routing constraints?

I hope someone can help! I am at the start of a long road in getting this application to Rails 5 ;)

How to cache a ActiveRecord model object which contains carrierwave uploader to Redis

I have a user model which has a carrierwave uploader for storing ths users profile picture

class User < ActiveRecord::Base
    mount_uploader :profilepic, LogoUploaderUploader

I want to cache this User object in redis. While caching I call the to_json method on the activerecord object which converts the profilepic field in the user object to a hash containing the url of the image

user={id:1, username: "sam", profilepic: {url:"path_to_image.jpg"}}

This part is fine and I can store it in redis. But the trouble comes when I retrieve the data from redis and try to convert it to a ActiveRecord object like the following

user=User.new(json_data)

The profilepic field comes null. Looks like it is not able to deserialize the profilepic hash profilepic: {url:"path_to_image.jpg"}to a proper value.

Is there anyway I can get back the proper value for profilepic after saving to redis.

Why Page and Action Caching has been removed from Rails 4?

Why Page Caching and Action Caching are removed from Rails 4.

How do we achieve the caching now after Rails 4 ?

mardi 13 juin 2017

Include select scope in outer join includes

Rails 3, I want to include a select scope in a join clause. Here's the code I have:

require 'logger'
require 'active_record'
require 'pg'

ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Schema.define do
  create_table :users, :force => true do |t|
    t.string :name
  end

  create_table :properties, :force => true do |t|
    t.integer :user_id, unique: true
    t.string :line1
    t.string :line2
  end
end

class User < ActiveRecord::Base
  attr_accessible :name
  has_one :property
end

class Property < ActiveRecord::Base
  belongs_to :user
  attr_accessible :address, :line1, :line2
  default_scope :select => "#{table_name}.*, #{table_name}.line1 || ', ' || #{table_name}.line2 AS address"
end

u = User.new(name: :a)
p = Property.new(line1: :y, line2: :z, user: u)
p.user = u
p.save

This line generates the following sql:

User.first.property.address

User Load (0.1ms)  SELECT "users".* FROM "users" LIMIT 1
Property Load (0.1ms)  SELECT properties.*, properties.line1 || ', ' || properties.line2 AS address FROM "properties" WHERE "properties"."user_id" = 1 LIMIT 1

But this line doesn't include the custom select scope with the computed column:

User.includes(:property).where('properties.address=?', 'y, z').first.property.address

SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "properties"."id" AS t1_r0, "properties"."user_id" AS t1_r1, "properties"."line1" AS t1_r2, "properties"."line2" AS t1_r3 
FROM "users" 
LEFT OUTER JOIN "properties" ON "properties"."user_id" = "users"."id" 
WHERE (properties.address='y, z') 
LIMIT 1

Any way to get it to do something like this?

LEFT OUTER JOIN (SELECT properties.*, properties.line1 || ', ' || properties.line2 AS address FROM "properties") AS "properties" ON "properties"."user_id" = "users"."id" 
WHERE (properties.address='y, z')