Elasticsearch, Tire & Associations - ruby-on-rails

Running: Ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-darwin11.2.0], Rails 3.2.0
I'm trying to get elastic search working through the TIRE gem across associations. For some reason I keep getting the following error/errors when performing a rake on a TIRE import or occasionally on a view:
Daves-MacBook-Pro:outdoor dave$ rake environment tire:import CLASS=Gear FORCE=true
[IMPORT] Deleting index 'gears'
[IMPORT] Creating index 'gears' with mapping:
{"gear":{"properties":{}}}
[IMPORT] Starting import for the 'Gear' class
--------------------------------------------------------------------------------
101/101 | 100% rake aborted!######################################
undefined method `last_name' for nil:NilClass
Tasks: TOP => tire:import
Here are my models:
GEAR
class Gear < ActiveRecord::Base
attr_accessible :title, :size, :price, :image_url, :sub_category_id, :user_id
belongs_to :user
belongs_to :sub_category
validates :title, presence: true
validates :size, presence: true
validates :price, presence: true
validates :sub_category_id, presence: true
validates :user_id, presence: true
include Tire::Model::Search
include Tire::Model::Callbacks
def self.search(params)
tire.search(load: true, page: params[:page], per_page: 18) do
query { string params[:query]} if params[:query].present?
end
end
def to_indexed_json
to_json(methods: [:sub_category_name, :user_last_name, :user_first_name, :user_email])
end
def sub_category_name
sub_category.name
end
def user_first_name
user.first_name
end
def user_last_name
user.last_name
end
def user_email
user.email
end
end
USER
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name, :email, :password, :password_confirmation
has_secure_password
has_many :gears
before_save :create_remember_token
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :first_name, presence: true,
length: {:maximum => 50 }
validates :last_name, presence: true,
length: {:maximum => 50 }
validates :email, presence: true,
format: {:with => email_regex},
uniqueness: {:case_sensitive => false}
validates :password, presence: true,
confirmation: true,
length: {within: 6..40}
def name
first_name + " " + last_name
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
Sub_Category
class SubCategory < ActiveRecord::Base
attr_accessible :name
belongs_to :category
has_many :gears
end
What am I missing? Thanks.

I had a few NIL values in my database that was the reason for the errors. Hopefully this can save a few people some time.

Related

Default value along with uniqueness validation

I have a Path model with name attribute as unique. I want to set default value as '/'
to the same.
I have done in the following manner.
class Path < ActiveRecord::Base
attr_accessible :name
validates :name, presence: true, uniqueness: true
before_validation :set_default_path
private
def set_default_path
self.name = name.presence || '/'
end
end
Domain model is designed as:
class Domain < ActiveRecord::Base
attr_accessible :name, path_id
validates :name, :path_id, presence: true
validates :name, uniqueness: {scope: :path_id}
end
But this doesn't work for consecutive inserts with a blank name for path.
path = Path.find_or_create_by_name('')
domain = Domain.new(name: 'stackoverflow.com')
domain.path = path
domain.save! # Fails with validation error
ActiveRecord::RecordInvalid:
Validation failed: Path can't be blank
Is there a robust way to achieve this ?
You should remove following callback
before_validation :set_default_path
and use validation for name as following:--
validates :name, presence: true, uniqueness: true, :if => 'name.present?'
and write a migration file to add default value to name attribute of paths table as either of followings:--
change_column :paths, :name, :string, :default => '/'
or
change_column_default :paths, :name, '/'
add condition on validation:
validates :name, presence: true
validates :name, uniqueness: true, unless: proc { |e| e.name == "/" }

Strong parameters in Ruby

I'm getting the error message about strong parameters. I think it's just that rails 4 doesn't use attributes anymore. the code for my toy.rb is:
class Toy < ActiveRecord::Base
attr_accessible :name, :price, :vendor
validates :name, :presence => true
validates :price, :presence => true
validates :price, :numericality => true
validates :vendor, :presence => true
end
how can I change this to strong parameters?
EDIT: I used a different rb i changed it to employees and this is what I have:
class Employee < ActiveRecord::Base
params.require(:employee).permit(:first, :last, :salary, :salary, :ssn)
validates :first, :presence => true
validates :last, :presence => true
validates :salary, :presence => true
validates :salary, :numericality => true
validates :ssn, :presence => true
end
It's still telling me "ndefined local variable or method `params' for #"
The code you need is
params.require(:toy).permit(:name, :price, :vendor)
You will put this in your controller. Typically, you create a private method:
def create
Toy.create(toy_params)
end
private
def toy_params
params.require(:toy).permit(:name, :price, :vendor)
end
See http://guides.rubyonrails.org/getting_started.html#saving-data-in-the-controller for more information.
Edit
I think I might have misled you with my original answer. The code goes in the controller, not the model.
Strong params are designed to help your controller send specific data to your model. It's meant to protect your app against unauthorized data being passed:
#app/controllers/toys_controller.rb
Class ToysController < ActiveRecord::Base
def new
#toy = Toy.new #-> creates a blank AR object
end
def create
#toy = Toy.new(toys_params) #->creates new AR object (populating with strong params)
#toy.save
end
private
def toys_params
params.require(:toys).permit(:your, :params, :here)
end
end

WARNING:"Can't mass-assign protected attributes: created_at, updated_at",when I use gem ''omniauth-identity"

I get this error
ActiveModel::MassAssignmentSecurity::Error in SessionsController#create
Can't mass-assign protected attributes: created_at, updated_at
I think I can add some codes to solve this problem.
class User < ActiveRecord::Base
attr_accessible :email, :nickname, :authentications_attributes, :created_at, :updated_at
Why Omniauth changes the created_at and updated_at?
In addition to add "attr_accessible :created_at, :updated_at", there are other ways?
This is my models/user.rb
class User < ActiveRecord::Base
attr_accessible :email, :nickname, :authentications_attributes, :created_at, :updated_at
validates :nickname, :presence => true
validates :email, :presence => true, :uniqueness => true
has_many :authentications
accepts_nested_attributes_for :authentications
class << self
def from_auth(auth)
Authentication.find_by_provider_and_uid(auth[:provider],
auth[:uid]).try(:user) ||
create!(
:nickname => auth[:info][:nickname],
:email => auth[:info][:email],
:authentications_attributes => [
Authentication.new(:provider => auth[:provider],
:uid => auth[:uid]
).attributes
])
end
end
end
This is my models/identity.rb
class Identity < OmniAuth::Identity::Models::ActiveRecord
attr_accessible :nickname, :email, :password, :password_confirmation, :authentications_attributes
validates_presence_of :nickname, :email
validates_uniqueness_of :nickname, :email
validates_format_of :email, :with => /^[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
end
This is my models/authentication.rb
class Authentication < ActiveRecord::Base
attr_accessible :user_id, :provider, :uid, :authentications_attributes, :created_at, :updated_at
validates :provider, :presence => true, :uniqueness => {:scope => :user_id}
validates :uid, :presence => true, :uniqueness => {:scope => :provider}
belongs_to :user
end
This is my controllers/sessions_controller.rb
class SessionsController < ApplicationController
def create
user = User.from_auth(request.env['omniauth.auth'])
session[:user_id] = user.id
flash[:notice] = "Welcome #{user.nickname}"
redirect_to root_path
end
end
Thanks for your thoughts and pointers.
The problem is this bit of code:
Authentication.new(:provider => auth[:provider],
:uid => auth[:uid]
).attributes
This will return the full set of attributes, including the created_at and updated_at dates, which you're then passing to create, so mass assigning.
You could create the user, then build the attributes like so:
authentication = Authentication.find_by_provider_and_uid(auth[:provider],
auth[:uid]).try(:user)
unless authentication
user = create!(
:nickname => auth[:info][:nickname],
:email => auth[:info][:email])
user.authentications.build(:provider => auth[:provider])
end

How to share validations accross models?

I have this validations in a model TipoMovimiento:
class TipoMovimiento < ActiveRecord::Base
before_validation :default_values
validates :codigo, :numericality => {:greater_than => 0}
validates :codigo, :descripcion, :sintetico, :presence => true
validates :codigo, :descripcion, :sintetico, :uniqueness => true
validates :descripcion, :length => {:minimum => 3}
validates :sintetico, :length => {:minimum => 2}
private
def default_values
self.estado ||= true if self.estado.nil?
self.codigo ||= TipoMovimiento.maximum(:codigo) + 1
end
end
Also, I have others models with the same fields, and I don't want to repeat these validations on them. How I do that?
I think you should use custom validations or inheritance.
What I would do is create a separate model:
module Validator
def self.included(base)
base.send :validates, :name, :presence => true
end
end
class User < ActiveRecord::Base
include Validator
end

Rails Nested Resource Routes

I'm fairly new to rails and I don't think I'm understanding the routing completely. When I try to access the edit action I get the following error:
ActiveRecord::RecordNotFound in StoreController#show
Couldn't find Gear with id=edit
Rails.root: /Users/dave/rails_projects/outdoor
Application Trace | Framework Trace | Full Trace
app/controllers/store_controller.rb:7:in `show'
Request
Parameters:
{"user_id"=>"104",
"id"=>"edit"}
Show session dump
Show env dump
Response
Headers:
None
Here is my view with the link that is throwing this error:
<li><%= link_to "Store Appearance", edit_user_store_path(#user) %></li>
Here is my nested route:
resources :users do
resources :store
end
Here is my controller
class StoreController < ApplicationController
def index
#store = current_user.gears.paginate(page: params[:page])
end
def show
#gears = Gear.find(params[:id]).user.gears.paginate(page: params[:page])
end
def edit
end
def update
end
end
Model Store
class Store < ActiveRecord::Base
attr_accessible :storeimage, :storename
belongs_to :user
validates :user_id, :presence => true
end
Model User
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name, :email, :password, :password_confirmation, :userimage, :remove_userimage
has_secure_password
has_many :gears
has_many :comments, :dependent => :destroy
has_one :store, :dependent => :destroy
before_save :create_remember_token
require 'carrierwave/orm/activerecord'
mount_uploader :userimage, UserpicUploader
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :first_name, presence: true,
length: {:maximum => 50 }
validates :last_name, presence: true,
length: {:maximum => 50 }
validates :email, presence: true,
format: {:with => email_regex},
uniqueness: {:case_sensitive => false}
validates :password, presence: true,
confirmation: true,
length: {within: 6..40}
include Tire::Model::Search
include Tire::Model::Callbacks
def name
first_name + " " + last_name
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
Please help.
You need to pass both the user_id and id params in the URL when you're accessing a store object nested under a user, so your URL should look like this:
/users/1/stores/3/edit
Versus:
/users/1/stores/edit
You also need to pass both of those as arguments to your path helper, ie:
edit_user_store_path(#user, #store)

Resources