Trouble defining finder method in my application - mysql

I’m using Rails 4.2.3 and MySQL 5.5.37. I want to write a finder method for my model, so I have written this (./app/models/user_object.rb):
class UserObject < ActiveRecord::Base
validates :day, :presence => true
validates_numericality_of :total
validates :object, :presence => true
def find_total_by_user_object_and_year
UserObject.sum(:total, :conditions => ['user_id = ?', params[:user_id], 'object = ?', params[:object], 'year(day) = ?', params[:year]])
end
end
However, when I attempt to invoke the method within a controller like so
#my_total = UserObject.find_total_by_user_object_and_year(session["user_id"], 3, #year)
I get the following error
undefined method `find_total_by_user_object_and_year' for #<Class:0x007fb7551514e0>
What is the right way to define my finder method?

Use self.method to define class method:
def self.find_total_by_user_object_and_year
sum(:total, :conditions => ['user_id = ?', params[:user_id], 'object = ?', params[:object], 'year(day) = ?', params[:year]])
end
In this case UserObject inside class method definition is redundant, besause it is same as self. Now you can write:
UserObject.find_total_by_user_object_and_year(params)

Related

Rails 4 Script + Error: Migrating Data From One Table to Another

I have created a script that I want to use to populate a new table in another database, as I'm moving this table out of one DB(table_1) and into another DB(db_2). I've already created the 'new_geo_fence' table in the new DB (db_2) and want to have the script run below to migrate data over. Script below:
class NewGeoFence < ActiveRecord::Base
attr_accessible :name, :address, :latitude, :longitude, :radius, :customer_id
belongs_to :customer, :foreign_key => 'customer_id'
end
require 'rubygems'
GeoFence.all.each do |g|
gf = NewGeoFence.new(
:id => g.id,
:name => g.name,
:address => g.address,
:latitude => g.latitude,
:longitude => g.longitude,
:radius => g.radius,
:created_at => g.created_at,
:updated_at => g.updated_at,
:customer_id => g.customer_id
)
gf.save
end
However, when I run it, I get this error:
/activerecord-4.0.13/lib/active_record/attribute_assignment.rb:47:in `rescue in _assign_attribute': unknown attribute: customer_id (ActiveRecord::UnknownAttributeError)
What have I missed to get this script running?
Thanks!
You're calling each on a class when you should be calling it on an array of objects, so
GeoFence.all.each do |g|
Rails 4 requires parameters to be whitelisted when doing mass assignment. To do so, use strong parameters
GeoFence.all.each do |g|
params = ActionController::Parameters.new({
geofence: {
id: g.id,
name: g.name,
address: g.address,
latitude: g.latitude,
longitude: g.longitude,
radius: g.radius,
created_at: g.created_at,
updated_at: g.updated_at,
customer_id: g.customer_id
}
})
gf = NewGeoFence.new(params.require(:geofence).permit!)
gf.save
end

Rails search a model based on multiple parameters using a form

So... I've been working on creating a search form for a rails application. I've gone through the railscast episodes 37, 111, and 112.
While the simple text search with a text input field works. I need to be able to define more parameters to refine the search.
I've found a few other methods, some using scopes...I keep running into issues getting any of these working in my application....
What I have right now is a simple form defined on my home index that points at my assets index:
<% form_tag assets_path, :method => 'get' do %>
<%= text_field_tag :search, params[:search] %>
<%= collection_select(:type_id, :type_id, Type.where("type_for = 'asset'"), :id, :name) %>
<%= submit_tag "Search", :search => nil %>
<% end %>
my asset.rb model:
class Asset < ActiveRecord::Base
has_many :children_assets, :class_name => "Asset"
has_and_belongs_to_many :groups, :join_table => "assets_groups"
belongs_to :parent_asset,
:class_name => "Asset",
:foreign_key => "parent_asset_id"
belongs_to :asset_type,
:class_name => "Type",
:conditions => "type_for = 'asset'"
belongs_to :asset_status,
:class_name => "Status",
:conditions => "status_for = 'asset'"
belongs_to :location
belongs_to :funding_source
has_many :transactions
def self.search(search)
if search
find(:all, :conditions => ['nmc_name LIKE ? AND type_id = ?', "%#{search}%", "%#{search}"])
else
find(:all)
end
end
end
in the asset_controller.rb
def index
unless params[:search].nil?
#title = "Assets"
#search = params[:search]
#assets = Asset.search(params[:search]).paginate(page: params[:page], per_page: 25)
else
#title = "Assets"
#assets = Asset.where('').paginate(page: params[:page], per_page: 25)
end
end
I just dont understand what it is that I'm not seeing here. I can run a similar mysql query and get the result I want. I just dont know how to format this in rails...
Any guidance on this would be amazing right now. Thanks!
It looks as though you're trying to search for a specific type of asset, but your search method in the Asset model is only using one of the user supplied parameters.
Judging by the form you're using, your controller will be receiving the params
params = {
search: 'Search Text',
type_id: 1
}
In your controller, you're only using search, so I'd change your method to include this:
#assets = Asset.search(params[:search], params[:type_id]).paginate(page: params[:page], per_page: 25)
Then amend the Assets model to use it
def self.search(search, type_id)
if search
find(:all, :conditions => ['nmc_name LIKE ? AND type_id = ?', "%#{search}%", "%#{type_id}"])
else
find(:all)
end
end

How can I save a unique string by incrementing it in rails?

How can I save a unique string to my database and if the value exists increment it.
The behaviour I'm after is similar to when you save a file e.g. foo.txt, foo1.txt
I do NOT want to return a 'not unique value' error message.
class Person < ActiveRecord::Base
attr_accessible :name
end
Person.create(:name => 'Dave') # => 'Dave'
Person.create(:name => 'Dave') # => 'Dave1'
Person.create(:name => 'Dave') # => 'Dave2'
I'm using ruby, rails and mysql
you don't need to set validation uniqueness to your model . You can use something like this:
class Person < ActiveRecord::Base
attr_accessible :name
before_create :check_and_increment
private
def check_and_increment
if Person.exists? name: self.name
similar_persons = get_all_with_same_name self.name
next_num = similar_persons.max_by{|m| m.scan(/\d+/)}.scan(/\d+/).first.nil? ? 1 : similar_persons.max_by{|m| m.scan(/\d+/)}.scan(/\d+/).first.to_i + 1
self.name = "#{self.name}#{next_num}"
else
true
end
end
def get_all_with_same_name name
where("name LIKE ?", 'name%')
end
end
This is simple idea for your problem. Need to be carefull with persons like Anna and Annastasia, for example . These persons has different names but their names are overlap.
Hope this will help you .
I could not find any rails or mysql features to do this so I created the follow 3 methods and
def unique_name(name)
if Person.exists?(:name => name)
generate_unique_name(name)
else
name
end
end
def similar_names(name)
Person.where("name LIKE ?", "#{name}%").pluck(:name)
end
def generate_unique_name(name)
number = similar_names(name).map{ |a| a.scan(/\d+$/).max.to_i }.compact.max.to_i + 1
"#{name} #{number}"
end
...
Person.create(:name => unique_name('Dave'))

Remove extra appended characters to a text stored in MySQL

I have an api controller that collects information from the api users. However, some user information when sent and stored in the MySQL database sometimes its appears with added underscores like this "this is a test ________" instead of this is a test. However when run through the browser it stores just fine.
What could be the problem.
Controller extract;
#message.message = CGI.unescape(params[:message]).strip
As a temporary fix, any ideas how i can strip away all the 6 underscores that are being added to the message either in storage or when it comes.
class Api::V1::Json::MessagesController < ApplicationController
before_filter :authenticate
require 'uri'
require 'cgi'
def sms
#message = Message.new
##message.to = decoded_to.gsub(/[^\d]/,"")
#message.to = CGI.unescape(params[:to]).strip.gsub("+","").gsub(/\s+/, "")
#message.from = CGI.unescape(params[:from])
#message.message = CGI.unescape(params[:message]).strip
#message.user_id = current_user.id
#message.status = 'Queued'
if #message.save
MessageWorker.perform_async(#message.id, [""], current_user.id)
render json: {status: "Success"}
else
render json: {status: "Failed" }
end
end
private
def authenticate
error!('Unauthorized. Invalid token.', 401) unless current_user
end
def current_user
# find token. Check if valid.
user_token = params[:token]
token = ApiKey.where(:access_token => user_token).first
if token
#current_user = User.find(token.user_id)
else
false
end
end
end
and the model is;
class Message < ActiveRecord::Base
attr_accessible :message, :phone, :status, :to, :from, :user_id
attr_accessor :schedule
validates :message, :presence => true
validates :from, :presence => true
validates :to, :presence => true
validates :status, :presence => true
validates_length_of :message, :maximum => 1600, :allow_blank => true
validates_length_of :from, :maximum => 11, :allow_blank => false
belongs_to :user
Change your Model like this
class Message < ActiveRecord::Base
before_save :strip_underscore
def strip_underscore
self.message.gsub("______","")
end
end

Ignore modules from Model

I have in my application a few controllers that i want to use as a api. In this api i need to use versioning.
in my routes.rb i`m using this:
require 'api_constraints'
(...)
scope '/:target/:version', :module => :api, :constraints => { :version => /[0-z\.]+/ } , :defaults => { :format => 'json' } do
scope :module => :v1, :constraints => ApiConstraints.new(:version => 1, :default => true) do
match '/list' => 'sample#list'
end
end
my api_constraints.rb:
class ApiConstraints
def initialize(options)
#version = options[:version]
#default = options[:default]
end
def matches?(req)
#default || req.headers['Accept'].include?("application/waytaxi.api.v#{#version}")
end
def self.version
#version
end
end
in my SampleController.rb:
module Api
module V1
class SampleController < ApiBaseController
def list
render json: Model.find_by_id(params[:id])
end
end
end
end
the ApiBaseController:
module Api
class ApiBaseController < ApplicationController
before_filter :authenticate
skip_before_filter :verify_authenticity_token
private
def authenticate
# if params[:target] == "ios"
# render :json => {status: 404}
# return false
# end
end
end
end
the problem is:
whenever i try to call Model i get this error:
uninitialized constant Api::V1::SampleController::Model
If i use: ::Model i get this error:
uninitialized constant Model
And yes, i do have this models on my database. If i use Model.all outside the SampleController i get the objects.
P.S.: I'm using rails 3.2.8
Found my problem.
My Model was in plural and on my controller i was calling it in singular