Private method select called for class - Rails - ruby-on-rails

I have the following code inside my controller:
array = Contact.select(:name).distinct
The idea is that this would create an array of all Contact models with a unique :name attribute. However, it's throwing this error:
NoMethodError (private method 'select' called for Contact:Class)
What's the misunderstanding here? For what it's worth, the method calling this line of code is not defined in the controller as private.
EDIT:
Here's the actual code:
Controller
class FluidsurveysController < ApplicationController
def index
end
def import_contacts
#survey_provider = FluidsurveysProviders::SurveyProvider.new()
#current_month = Time.new.strftime("%B%Y%d")
fs_contact_list_array = csv_to_array(params[:file].tempfile)
#fs_contacts_array = []
fs_contact_list_array.each do |hash|
#fs_contacts_array << Contact.new(hash)
end
array = Contact.select(:name).distinct
end
end
Model
class Contact
include ActiveModel::Model
attr_reader :client_id, :client_name, :branch_id, :branch, :short_name, :unit_id, :membership_id,
:first_name, :last_name, :date_of_birth, :change_date_time, :membership_type,
:home_phone, :email_address, :anniversary_years
def initialize(fs_contact_hash = {})
#client_id = fs_contact_hash.fetch('ClientID')
#client_name = fs_contact_hash.fetch('ClientName')
#branch_id = fs_contact_hash.fetch('branchID1')
#branch = fs_contact_hash.fetch('branch')
#name = fs_contact_hash.fetch('ShortName')
#unit_id = fs_contact_hash.fetch('UnitID')
#membership_id = fs_contact_hash.fetch('MemberID')
#first_name = fs_contact_hash.fetch('FirstName')
#last_name = fs_contact_hash.fetch('LastName')
#date_of_birth = fs_contact_hash.fetch('DateOfBirth')
#change_date_time = fs_contact_hash.fetch('ChangeDateTime')
#membership_type = fs_contact_hash.fetch('MembershipType')
#home_phone = fs_contact_hash.fetch('HomePhone')
#email_address = fs_contact_hash.fetch('EMail1')
#anniversary_years = fs_contact_hash.fetch('Years')
end
end

Based on your error message I am pretty sure your model is not an ActiveRecord Object.
If you want to make use of ActiveRecord#select, define your model like this.
class Contact < ActiveRecord::Base
Also you need to define your attributes in a database instead of via attr_reader to access them through ActiveRecord. See http://guides.rubyonrails.org/getting_started.html#running-a-migration

You seem to be using an older version of Rails, specifically version 2.3.whatever. There, the select method is indeed private on the ActiveRecord model classes (as it is inherited from the Kernel module which is part of every Ruby object and serves a wholly different purpose) and thus isn't intended to be used like it is done in Rails 3 and Rails 4.
In Rails 2.3, you can achieve similar results using this syntax:
Contact.all(:select => "DISTINCT name")
This will return an array of Contacts which have only the name attribute set.

Related

Meetup API using RoR. Getting NameError: uninitialized constant Event in the rails console

Looking for some help with the Meetup.com API I'm trying to add to my Rails app. My purpose is just to have a view of local meetups when you open the app.
Here is my code so far:
Routes.rb (at the bottom before the last 'end'):
root 'meetup#get_meetup'
meetup_controller.rb
class MeetupController < ApplicationController
def get_meetup
if params[:city] && params[:name]
#Event = Event.new(params[:city], params[:name])
else
#event = Event.new("90034", "networking")
end
end
end
meetup.rb:
class Event
attr_reader :city, :nam
def initialize(city, name)
url = "http://api.meetup.com/2/events?key#{ENV["meetup_api_key"]}&group_urlname=Girl-Develop-It-Austin&sign=true.json"
response = HTTParty.get(url)
#event = response["event"]
#city = city
#name = name
end
end
I tried to create a new event search using the params for the city and name (aka the event categories) in the rails console.
rails console:
Event.new("Austin", "networking")
and it gave me the error NameError: uninitialized constant Event
**I'm still new to using third party API's especially with Rails so I haven't found too much information online about how to correctly get them to work. If someone could please give me some insight into why this isn't correct...or if theres a great article/website to help me with these please let me know!!
Try to move your code into service object
Create a folder services inside app folder. Then move your Event class to service folder. Also in initialize method, a good practice is you initialize only the variable. For parsing creating another method.And lastly, you have done a spelling mistake which I have corrected
class Event
include HTTParty
attr_reader :city, :name ##you have made a spelling mistake
def initialize(city, name)
#city = city
#name = name
end
def parsing
url = "http://api.meetup.com/2/events?key#
{ENV["meetup_api_key"]}&group_urlname=Girl-Develop-It-
Austin&sign=true.json"
response = HTTParty.get(url)
#event = response["event"]
end
end
Restart the server after copy pasting, personally never tried to use meetup api.
controller
Meetup.new(city, name)
/config/application.rb
config.eager_load_paths << Rails.root.join('lib')
/lib/meetup.rb
require 'rest-client'
require 'net/http'
require 'json'
class Meetup
attr_reader :city, :name
def initialize(city, name)
resp = RestClient.get("http://api.meetup.com/2/events?key#{ENV['meetup_api_key']}&group_urlname=Girl-Develop-It-Austin&sign=true.json")
#or
resp = RestClient.get("http://api.meetup.com/2/events",
{ key: ENV['meetup_api_key'],
group_urlname: "Girl-Develop-It-Austin",
sign: true
})
#event = JSON.parse(resp, { symbolize_names: true })[:event]
#city = city
#name = name
end
end
You need to restart your rails console using reload! also you've mentioned above meetup.rb file which includes
class MeetUp #you need to change class name
attr_reader :city, :name
def initialize(city, name)
url = "http://api.meetup.com/2/events?key#ENV["meetup_api_key"]}&group_urlname=Girl-Develop-It-Austin&sign=true.json"
response = HTTParty.get(url)
#event = response["event"]
#city = city
#name = name
end
end
If your filename is meet_up.rb the class name must MeetUp not Event Please change your class name or else you can change filename as event.rb
You can not define model or inside class as different name I hope my answer will help you. Thanks
Class name should be file_name_except_extension.classify. Therefore it would be 'meet_up'.classify i.e. MeetUp and not Event

what implications have redefining *_before_type_cast in an activerecord model

Let's say I want to redefine a method in a model:
class Model < ActiveRecord::Base
attr_accesor :model_attr
def model_attr
'redefined'
end
end
When I access it directly, it works as it is supposed to, but when I call it from the view:
f.text_field :model_attr
It doesn't. But this still works:
f.text_field :model_attr, value: #model.model_attr
So I had to dig into Rails code:
def text_field(object_name, method, options = {})
Tags::TextField.new(object_name, method, self, options).render
end
to
class TextField < Base # :nodoc:
def render
options = #options.stringify_keys
options["size"] = options["maxlength"] unless options.key?("size")
options["type"] ||= field_type
options["value"] = options.fetch("value") { value_before_type_cast(object) } unless field_type == "file"
options["value"] &&= ERB::Util.html_escape(options["value"])
add_default_name_and_id(options)
tag("input", options)
end
and
def value_before_type_cast(object)
unless object.nil?
method_before_type_cast = #method_name + "_before_type_cast"
object.respond_to?(method_before_type_cast) ?
object.send(method_before_type_cast) :
value(object)
end
end
Okay, so it looks like text_field is not accessing the attribute directly, but rather appending _before_type_cast. I've read the documentation, but still do not understand why this is necessary for #text_field? I can do this, and it works:
class Model < ActiveRecord::Base
attr_accesor :model_atr
def model_attr
'redefined'
end
def model_attr_before_type_cast
model_attr
end
end
If I redefine both methods, can I get in trouble somehow in the future? Is there a better way to do this?
The reason for using *_before_type_cast is found on the description of this commit :
Added use of *_before_type_cast for all input and text fields. This is helpful for getting "100,000" back on a integer-based
+ validation where the value would normally be "100".

how do I override create action with variables generated inside the controller in rails 4

This is the code that I have written in the create action of Payments Controller.
user_id=Performer.find_by_first_name(params[:payment][:first_name]).user.id
email=Performer.find_by_first_name(params[:payment][:first_name]).user.email
#payment = Payment.new(user_id,params[:payment][:desc],params[:payment][:amount],email,params[:first_name])
##payment = Payment.new(payment_params)
When I try this I get the following error:
wrong number of arguments (5 for 0..1)
I cannot just pass the values of as such so I need to change them before I save it in the table. How do I do this?
It only accepts an hash of attributes:
#payment = Payment.new(
user_id: user_id,
desc: params[:payment][:desc],
amount: params[:payment][:amount],
email: email,
first_name: params[:first_name]
)
Since you are using Rails 4, I encourage you to take a look at strong_parameters.
Changing the values before saving them in the db
You can either use a before_save callback or defining custom accessors.
1. Using before_save callbacks:
If you want to change the values before saving them in the database, you can use a before_save callback:
class Payment < ActiveRecord::Base
before_save :change_values
private
def change_values
self.amount = amount.do_something
# etc.
end
end
API documentation:
ActiveRecord::Callbacks
2. Using custom accessor:
Or you can define custom accessor:
2.1 With read_attribute and write_attribute
def amount=(dollars)
write_attribute :amount, dollars.do_something
end
def amount
read_attribute(:amount).do_something
end
API documentation:
read_attribute
write_attribute
2.2 With virtual attributes:
def amount_in_dollars
amount.do_something
end
def amount_in_dollars=(dollars)
self.amount = dollars.do_something
end
Railscasts:
Virtual Attributes
Virtual Attributes (revised)
#payment = Payment.new(:column_1 => value/params[:],:column_2 => params[:desc])
if it is a form submit
#payment = Payment.new(param[:payment])
out side form submit
#payment.column_1 = value

Post failing with a nested resource from Ember.js to a Rails API.

I have a nested resource called App.Routine that has_many activities. When I send the post here is my payload:
{routine: {name:testName,activities:[{name:testName},{name:testName}]}}
This returns a 500 error:
ActiveRecord::AssociationTypeMismatch in RoutinesController#create
Activity(#32627220) expected, got ActiveSupport::HashWithIndifferentAccess(#33577656)
My Rails API is using ActiveModelSerializers:
class RoutineSerializer < ActiveModel::Serializer
attributes :id, :name
has_many :activities, embed: :ids
end
class RoutinesController < ApplicationController
respond_to :json
def create
routine = Routine.create(params[:routine])
end
I believe my problem lies with how I handle the create action in my routines_controller.rb. Rails isn't liking how I am returning the hash of activities inside the routine JSON, but I can't figure out the correct way to handle this.
My original problem was indeed with my Rails API. I followed #dgeb's example again and realized I didn't know much about strong parameters. Thankfully there's a Railscast for that! Once I implemented that correctly I'm good to go!
Added 'gem strong_parameters' to my Gemfile. Then, my #create function on the parent controller makes a call to the update_parameters function where I first create and save the parent, then iterate through the child and save it.
From Dan Gebhart's ember data example:
def permitted_params
params.require(:contact).permit(:first_name,
:last_name,
:email,
:notes,
phone_numbers: [:id, :number])
end
def update_contact(contact)
contact_params = permitted_params
phone_numbers_param = contact_params.extract!(:phone_numbers)
phone_numbers_param = phone_numbers_param[:phone_numbers]
phone_numbers_param ||= []
# Because updates to the contact and its associations should be atomic,
# wrap them in a transaction.
Contact.transaction do
# Update the contact's own attributes first.
contact.attributes = contact_params
contact.save!
# Update the contact's phone numbers, creating/destroying as appropriate.
specified_phone_numbers = []
phone_numbers_param.each do |phone_number_params|
if phone_number_params[:id]
pn = contact.phone_numbers.find(phone_number_params[:id])
pn.update_attributes(phone_number_params)
else
pn = contact.phone_numbers.create(phone_number_params)
end
specified_phone_numbers << pn
end
contact.phone_numbers.each do |pn|
pn.destroy unless specified_phone_numbers.include?(pn)
end
end
# Important! Reload the contact to ensure that changes to its associations
# (i.e. phone numbers) will be serialized correctly.
contact.reload
return true
rescue
return false
end

Initializing an ActiveRecord object without overriding initialize

I quickly ran into problems when trying to create an ActiveRecord instance that overrode initialize like this:
class Email < ActiveRecord::Base
belongs_to :lead
def initialize(email = nil)
self.email = email unless email.nil?
end
end
I found this post which cleared up why it is happening.
Is there anyway that I can avoid creation code like this:
e = Email.new
e.email = "info#info.com"
I would like to create and initialise my objects in one line of code preferably.
Is this possible?
e = Email.new(:email => "info#info.com")
ActiveRecord::Base#new also takes a handy block variation
email = Email.new do |e|
e.email = params[:email] unless params[:email].blank?
end
The suggestions of using the hash version in prior answers is how i typically do it if I don't want to put any logic on the actual assignment.

Resources