uninitialized constant on a simple model attribute - ruby-on-rails-3

Probably an easy one.
Consider this simple rails model
class Something < ActiveRecord::Base
attr_accessible :URL, :name
validate :name, presence: true
validate :URL, presence: true
It is a complete ressource, in routes:
resources :something
created with :
rails generate scaffold something name:string URL:string
The line:
validate :URL, presence: true
keep throwing error:
uninitialized constant Something::URL
I really don't know what to do
Thanks

It most likely doesn't like the fact that URL is uppercase. (It thinks it's a class name).
It's against the convention and RoR is very big on conventions.

Related

Returning Columns from Associated Table in Model.all

Summary:
I have a model with a few "belongs_to" associations and when I call Model.all (or another custom method if need be) I want to not only return all columns of Model, but also one column from each of the associated Models. Basically instead of just returning the ID's of the associated Models I want to get a more friendly attribute like "name".
Using Rails 3.2.x
Model Details:
I have five models, basically for data normalization.
class ActionItem < ActiveRecord::Base
belongs_to :action_item_status
belongs_to :prod_ops_acceptance
belongs_to :action_item_priority
belongs_to :incident_ticket
<truncated the rest>
end
class IncidentTicket < ActiveRecord::Base
attr_accessible :number
has_many :action_items
validates_presence_of :number
end
class ActionItemPriority < ActiveRecord::Base
attr_accessible :name
has_many :action_items
validates_presence_of :name
end
class ActionItemStatus < ActiveRecord::Base
attr_accessible :name
has_many :action_items
validates_presence_of :name
end
class ProdOpsAcceptance < ActiveRecord::Base
attr_accessible :name
has_many :action_items
validates_presence_of :name
end
Attempted Solutions:
I've tried many combinations of things including using ActionItem.includes and ActionItem.joins to no avail. The latest thing I tried is (trying only for the 'number' attribute of the IncidentTicket model to start with...)
ActionItem.all(
select: 'action_items.title, incident_tickets.number',
joins: 'INNER JOIN incident_tickets
ON action_items.incident_ticket_id = incident_tickets.id')
The above only returns the 'title' attribute from the ActionItem model and not the 'number' attribute from the IncidentTicket model despite the SQL looking correct. It seems like the SELECT on the joined table is completely ignored no matter what I try.
Obviously I am seriously missing something here or doing this completely wrong. I feel like there is some ActiveRecord magic that I'm missing out on that makes this trivial. Any help would be much appreciated! Please let me know if you need more details, I feel like this is kind of difficult to explain...
This ought to work for you:
action_items =
ActionItem.joins(:incident_ticket, :action_item_priority, ...)
.select(%[ action_items.title,
incident_tickets.number AS incident_ticket_number,
action_item_priorities.name AS action_item_priority_name,
... ]
)
.all
logger.info(action_items.first.incident_ticket_number)
What I ended up doing for now is creating a method that returns an array containing the results of ActionItem.all with the additional attributes I want injected in. This can probably be optimized, but I haven't spent any more time focusing on that just yet:
def self.all_with_extras
action_items_with_extras = []
action_items = ActionItem.all.to_json
JSON.parse(action_items).each do |ai|
extras = {
'incident_ticket_number' => IncidentTicket.find(ai['incident_ticket_id']).number,
'status' => ActionItemStatus.find(ai['action_item_status_id']).name,
'priority' => ActionItemPriority.find(ai['action_item_priority_id']).name,
'acceptance' => ProdOpsAcceptance.find(ai['prod_ops_acceptance_id']).name
}
with_extras = ai.merge(extras)
action_items_with_extras.append(with_extras)
end # each
action_items_with_extras
end # def

FriendlyId suggest

I want to use FriendlyId to achieve this localhost3000/users/edu/profile but I do not know how to do it!
I have these models User and UserProfile
class User < ActiveRecord::Base
has_one :user_profile, :dependent => :destroy
extend FriendlyId
friendly_id :name, :use => :slugged
end
class UserProfile < ActiveRecord::Base
attr_accessible :user_id, :name, :surname, :nickname
belongs_to :user
end
How do I load in name of User the name of UserProfile? and
How do you update name of User when the name of UserProfile changes?
For the first I used
class User < ActiveRecord::Base
...
def name
if user_profile
"#{user_profile.name}"
end
end
But I can't make it change when I update or create a new Profile in UserProfile.
Using Ruby 1.9.3 and Rails 3.2.13.
If I understood it correctly, your problem is about sharing data between models, not about FriendlyId.
It seems delegate is your best bet here. It's a method in ActiveSupport that allows one model to expose another model's methods as their own.
class User < ActiveRecord::Base
delegate :name, :name=, :to => :user_profile
end
Reference: http://api.rubyonrails.org/classes/Module.html#method-i-delegate
The reason to delegate both :name and :name= is that the former method allows you to read from that attribute (getter), while the latter allows you to write to it (setter).
Before making these changes you'll want to run a migration to remove the name field from the users table in the database, since from now on you'll be using the data in the other model.
rails g migration remove_name_from_users name:string

My has_many model is causing ActiveAdmin to look for a foreign key on the has_on side

I'm new to ruby on rails (and ruby) and I'm trying to get ActiveAdmin working with my model. I've got a lot of the simple stuff working, but ActiveAdmin (on ActiveRecord) is giving me the following error and I cannot figure out why (I'm sure I've misconfigured something, but I don't know what):
Mysql2::Error: Unknown column 'assessment_styles.assessment_definition_id' in 'where clause': SELECT assessment_styles.* FROM assessment_styles WHERE assessment_styles.assessment_definition_id = 1 LIMIT 1
The AssessmentDefinition Model
class AssessmentDefinition < ActiveRecord::Base
attr_accessible :active, :endDOW, :endDate, :isForResearch, :name, :startDOW, :startDa>
has_one :assessmentStyle, :inverse_of => :assessment_definitions
has_one :consentForm
validates :name, :endDOW, :startDOW, :endDate, :startDate, :presence => true
has_and_belongs_to_many :courses
has_and_belongs_to_many :groups
has_and_belongs_to_many :behaviours
end
The AssessmentStyle Model
class AssessmentStyle < ActiveRecord::Base
attr_accessible :name
has_many :assessment_definitions, :inverse_of => :assessmentStyle
end
What am I doing wrong?
Oops! I figured it out (with a little help from Duane's Brain). I was misunderstanding has_one vs. belongs_to, having confused it with the plain English sense of the word and not having realised what it was doing under the hood.

Rails 3 Validation on Stored attributes

Well, we all know the new amazing feature of last ActiveRecord::Store class.
But how can we do validations safely? Here an example:
class User
has_many :posts
end
class Post
belongs_to :user
store :composed_attribute, accessors: [:attribute_1, :attribute_2]
validates :attribute_1, presence: true # This works great!
validates :attribute_2, presence: true, uniqueness: {scope: :user_id, message: "must be unique."} # This fails!
end
The first validation works great, but the second fails with and undestandable undefined method 'text?' for nil:NilClass.
In database everything is stored in yaml format. but we cannot be sure about the order, so which is the best way to perform such validation?
Disclaimer
I know that, maybe, in this case store the attributes together is not a great idea, mostly for performance issues, but it's an interesting topic anyway.

Active record::relation instead of the object's class, when using where method with Rails 3

I am trying to get the attributes of the objects after calling a .where query. The query is the following:
#matchers = TutoringSession.where(:begin_time_hour => 21).limit(5)
I get an array of tutoring sessions as a result. But I would like to be able to return only specific attributes of each of the matching tutoring sessions. So I have the following code in my view:
#matchers.each do |matcher|
matcher.begin_time_hour
end
Instead of listing each of matcher's begin_time_hour attributes, it all of the attributes for each matcher object. I have experimented with this block trying "puts matchers.begin_time_hour," and have also tried using partials to solve this problem, however I keep running into issues. If I ask #matcher.class, it says, it is ActiveRecord::Relation object. I thought it would be a TutoringSession object.
Here are my models, in case this helps.
require 'date'
class TutoringSession < ActiveRecord::Base
belongs_to :refugee
belongs_to :student
before_save :set_day_and_time_available, :set_time_available_hour_and_day
attr_accessor :begin_time, :book_level, :time_open
attr_accessible :time_open, :day_open, :tutoring_sessions_attributes, :page_begin, :begin_time
end
and my other class is the following
require 'date'
require 'digest'
class Refugee < ActiveRecord::Base
has_many :tutoring_sessions
has_many :students, :through => :tutoring_sessions
accepts_nested_attributes_for :tutoring_sessions, :allow_destroy => true
attr_accessible :name, :email, :cell_number, :password, :password_confirmation, :day_open, :time_open, :tutoring_sessions_attributes
end
Please let me know if you need more info. Thanks for the help!
It looks like you're not outputting anything to the view. By calling
#matchers.each do |matcher|
matcher.begin_time_hour
end
you get the result from running the loop, which is the relation, instead of the data. You are accessing begin_time_hour, but you aren't doing anything with it. You'd need something more like this to display the begin_time_hour fields.
<% #matcher.each do |matcher| %>
<%= matcher.begin_time_hour %>
<% end %>
By the way, #matchers should be an ActiveRecord::Relation object, a representation of the sql query that will be generated from the where and limit clauses. Calling all on the relation with make it an array of TutoringSession objects
#matchers = TutoringSession.where(:begin_time_hour => 21).limit(5).all
Calling each implicitly runs the query and iterates over the TutoringSession objects, so you shouldn't need to worry about that though.