Getting data from an instance of a model in Rails - sql

I am pretty new to Rails and I am lost right now.
I was following the blog tutorial, utilizing the information to create a different application which is kinda similar.
Well, what I want (in SQL language) is:
select planned from hourplans where area_id = 2 and time = '9:00:00'
There are 4 Models in my Application (it is basically the application from the blog tutorial put twice on the same website):
Productions (which can have multiple downtimes) [Production] --1-------N-- [Downtime]
class Production < ActiveRecord::Base
has_many :downtimes, dependent: :destroy
validates :items, presence: true
end
Production has the Attributes: Date(date), Time(time), Area(text) and Items(integer)
class Downtime < ActiveRecord::Base
belongs_to :production
end
Downtime has the Attributes Username(text), Category(text), Machine(text), Station(text), Minutes(integer) and Details(text)
Areas (which can have multiple hourplans) [Area] --1-------N-- [Hourplan]
class Area < ActiveRecord::Base
has_many :hourplans, dependent: :destroy
validates :title, presence: true
end
Area has the Attributes Title(text), Text(text)
class Hourplan < ActiveRecord::Base
belongs_to :area
end
Hourplan has the Attributes Time(time), Cycle(decimal), Minutes(integer) and Planned(integer)
So for example there is an object for the production from 9:00 to 10:00, production has a field called "area" which has the value 'area2'.
And there is also a object of Area which has the title 'Area2' which is related to an object Hourplan that has a field called 'planned' with the value of items that are planned(like 600) from 9:00 to 10:00.
How can I fetch that data into the show-page of the production from 9:00 to 10:00?
I can't get it to transfer.
I tried something like:
<% area2.hourplans.where("time = 09:00").select(:planned) %>
but that didnt work.
Then I thought I had to set the object of the model to a variable first, so I tried:
<% area = Area.find_by title: #production.area %>
But I just dont get it. I dont know whether this worked or not. But how can I get to the hourplans now? Those are related to the Areas
I also tried:
<%= Hourplan.select("planned").where("time = 9:00 AND area_id = 2") %>
and that just gave me:
#<Hourplan::ActiveRecord_Relation:0x50c23e0> and I dont know what that means, I thought I would have gotten a value out of the SQL Table, like '600'
I hope I made myself clear and understandable. If you have any questions please let me know. I would really appreciate your help, I was looking through the official guides but I can't really find what I am looking for.

You may try to replace
<%= Hourplan.select("planned").where("time = 9:00 AND area_id = 2") %>
by
<%= Hourplan.where("time = '9:00' AND area_id = 2").first.planned %>
Indeed, the where method returns a relation, which represents (roughly) the result of a SQL query. But you know that an SQL query may or may not return a single line. Generally, there are several rows returned. That's why you'll want to add first, to get only the first Hourplan object.

Related

Adding a column Migration with a default value in ruby on rails

I am using SQLite3 and I would like the following to work:
class AddNameToGoal < ActiveRecord::Migration
def change
add_column :goals, :goal_name, :text, default: goal.exercise.name
end
end
Or maybe this makes more sense as what I'm trying to do:
add_column :goals, :gname, :text, default: Goal.find(row_id).exercise.name
How do I get the above to work.
I doubt it will work as it is but that's what I want.
Specifically, The user is associated with an Exercise through the exercise_id column.
belongs_to :user
belongs_to :exercise
has_many :workouts, dependent: :destroy
(This is the model for Goal)...
I would like the user to be able to choose their own name for the Goal but I can give them the hint to name the goal after the Exercise's name and if they choose to leave it blank it will default to the exercise's name. More importantly this must happen on the SQL side so that later when I have a collection drop down which requires a name of the goal they will need a name which corresponds to the exercise.
<%= f.collection_select(:goal_id, #goals, :id,
:goal_name, :include_blank => "Please Select") %>
The Exercise Model is made in Rails to have
id, Name, other columns.
Exercise Model:
class Exercise < ActiveRecord::Base
has_one :goal
Is there a strategy by which that is possible.
Another option would be to help me find a strategy for active record so that I can do:
<%= f.collection_select(:goal_id, #goals, :id,
:goal_name, :include_blank => "Please Select") %>
with (something else to replace goal_name with Exercise.name like goal.exercise.name and goal.id and show only the ID.
Doing this when you define the column on the table is problematic. I definitely think doing it upon creation, in the model, is how you'd want to go.
You might also check out the default_value_for gem and see if it helps.
Hi so in case any body ever wants to do this:
I figured out a strategy...
This is perfect for anything that has an instance of name in terms of the user.
For example, you have something that tracks your Car and you want to give that Car by default the name which comes from that Car's Make_and_Model (model) in Rails.
Naturally when someone says they have a new "Honda Accord" then they get to have that name, but if they ever want to change it to "Lucy" because her name is Lucy and you better treat her with the respect she deserves!, then this gives you the option to do that.
You do not want to change the name for that whole Make&Model you only want to change the name for that specific car.make_and_model which belongs_to User.
If you are wanting something to have a name that defaults to another name but allows the user to change that. Do that on the model level... by setting a before_save method inside the model... like so:
before_save :default_values
def default_values
self.goal_name = self.exercise.name if self.goal_name.nil?
end

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.

Rails 3 - associations

I print in my view a number that tell me, how many people read my article. It looks something like a:
<%=article.hits.count%>
As is possible to see, I created a simple association.
Now I am trying to get the information, if the user who is log in on my page, so if he is already had read this article. In my table that contains hits is column user_id.
But I can't still find the way, how to get...
I tried something like:
<% if session[:login_user_id].hits.user_id == session[:login_user_id]%>
Have you read it already.
<% end %>
But the example above doesn't work me... Could anyone help me please, how to do?
EDIT: The models:
class Article < ActiveRecord::Base
has_many :hits
end
class Hits < ActiveRecord::Base
belongs_to :article, :class_name => "DataHit", :foreign_key => "article_id"
has_many :users
end
class User < ActiveRecord::Base
belongs_to :hit
end
Thanks in advance
Let's first talk about the model you like to receive. For me, it sounds like:
Every article can be visited / read by many users.
Every user can read / visit many articles.
This is a classical n:m-association which is normally implemented by a has-many-through association.
If this is the intention, it should be implemented like:
class Article < ActiveRecord::Base
has_many :hits
has_many :users, :through => :hits
end
class Hits < ActiveRecord::Base
belongs_to :article, :class_name => "DataHit", :foreign_key => "article_id"
belongs_to :user
end
class User < ActiveRecord::Base
has_many :hits
has_many :articles, :through => :hits
end
Of course, you have to add migrations that ensure that the final DB model is like that:
Hit has article_id and user_id to ensure that users may find the articles they have read
If you have that model implemented, it should be more easy. Then you have operations available like: #article.users.contains(User.find(user_id)). Have a look at the tutorial at Ruby on Rails Guides which explain what the has-many-through relation is and which advantages they have.
It would be helpful if you try the things first in the console of Rails. To do that, start with:
Start the rails console in the root directory of your application: rails c
Enter there e.g.: art = Article.find(1) to get the article with the id.
Try which methods are available: art.methods.sort to see all methods that could be used. If there is no method users, you have did something wrong with the assocication.
Try the call: us = art.users and look at the result. It should be a rails specific object, an object that behaves like a collection and understands how to add and remove users to that collection (with the whole life cycle of rails). The error your currently have could mean different things:
Your database model does not match your associations defined in Rails (I suspect that).
Some minor tweak (misspelling somewhere) which hinders Rails.
I hope this gives you some clues what to do next, I don't think that we can fix the problem here once and for all times.

Modeling inheritance with Ruby/Rails ORMs

I'm trying to model this inheritance for a simple blog system
Blog has many Entries, but they may be different in their nature. I don't want to model the Blog table, my concern is about the entries:
simplest entry is an Article that has title and text
Quote, however, does not have a title and has short text
Media has a url and a comment...
etc...
What is a proper way to model this with Ruby on Rails? That is
Should I use ActiverRecord for this or switch to DataMapper?
I would like to avoid the "one big table" approach with lots of empty cells
When I split the data into Entry + PostData, QuoteData etc can I have belongs_to :entry in these Datas without having has_one ??? in the Entry class? That would be standard way to do it in sql and entry.post_data may be resolved by the entry_id in the postdata table.
EDIT: I don't want to model the Blog table, I can do that, my concern is about the entries and how would the inheritance be mapped to the table(s).
I've come across this data problem several times and have tried a few different strategies. I think the one I'm a biggest fan of, is the STI approach as mentioned by cicloon. Make sure you have a type column on your entry table.
class Blog < ActiveRecord::Base
# this is your generic association that would return all types of entries
has_many :entries
# you can also add other associations specific to each type.
# through STI, rails is aware that a media_entry is in fact an Entry
# and will do most of the work for you. These will automatically do what cicloon.
# did manually via his methods.
has_many :articles
has_many :quotes
has_many :media
end
class Entry < ActiveRecord::Base
end
class Article < Entry
has_one :article_data
end
class Quote < Entry
has_one :quote_data
end
class Media < Entry
has_one :media_data
end
class ArticleData < ActiveRecord::Base
belongs_to :article # smart enough to know this is actually an entry
end
class QuoteData < ActiveRecord::Base
belongs_to :quote
end
class MediaData < ActiveRecord::Base
belongs_to :media
end
The thing I like about this approach, is you can keep the generic Entry data in the entry model. Abstract out any of the sub-entry type data into their own data tables, and have a has_one association to them, resulting in no extra columns on your entries table. It also works very well for when you're doing your views:
app/views/articles/_article.html.erb
app/views/quotes/_quote.html.erb
app/views/media/_media.html.erb # may be medium here....
and from your views you can do either:
<%= render #blog.entries %> <!-- this will automatically render the appropriate view partial -->
or have more control:
<%= render #blog.quotes %>
<%= render #blog.articles %>
You can find a pretty generic way of generating forms as well, I usually render the generic entry fields in an entries/_form.html.erb partial. Inside that partial, I also have a
<%= form_for #entry do |f| %>
<%= render :partial => "#{f.object.class.name.tableize}/#{f.object.class.name.underscore}_form", :object => f %>
<% end %>
type render for the sub form data. The sub forms in turn can use accepts_nested_attributes_for + fields_for to get the data passed through properly.
The only pain I have with this approach, is how to handle the controllers and route helpers. Since each entry is of its own type, you'll either have to create custom controllers / routes for each type (you may want this...) or make a generic one. If you take the generic approach, two things to remember.
1) You can't set a :type field through update attributes, your controller will have to instantiate the appropriate Article.new to save it (you may use a factory here).
2) You'll have to use the becomes() method (#article.becomes(Entry)) to work with the entry as an Entry and not a subclass.
Hope this helps.
Warning, I've actually used Media as a model name in the past. In my case it resulted in a table called medias in rails 2.3.x however in rails 3, it wanted my model to be named Medium and my table media. You may have to add a custom Inflection on this naming, though I'm not sure.
You can handle this easily using ActiveRecord STI. It requires you to have a type field in your Entries table. This way you can define your models like this:
def Blog > ActiveRecord::Base
has_many :entries
def articles
entries.where('Type =', 'Article')
end
def quotes
entries.where('Type =', 'Quote')
end
def medias
entries.where('Type =', 'Media')
end
end
def Entry > ActiveRecord::Base
belongs_to :blog
end
def Article > Entry
end
def Quote > Entry
end
def Media > Entry
end

Multi Model Form in Rails 3

I'm still a bit of a n00b when it comes to rails, however, I do have a question as to how to go about a multi-model form.
Basically, I have an event, and the user needs to be able to register for the event and provide a credit card for charging the event to. The credit card (I won't be holding the actual data for the CC, authorize.net will, but I need to keep a token representing the card) will live with the user so they can sign up for other events in the future. So, I want the user to be able to edit this in the future, and the card isn't specific to a single event. This doesn't seem like something I'd use nested routes with, does it?
I have a feeling this is fairly simple, but I guess I'm just not entirely sure how to do it. Can I used nested models (not routes) and still update each portion independently?
If I understand your question, then yes you can. I think you mean something like this:
class User < ActiveRecord::Base
has_one :credit_card
end
If that's correct, then the first step is to add this to the User class:
class User < ActiveRecord::Base
has_one :credit_card
accepts_nested_attributes_for :credit_card
end
At this point you could just set up a "users" resource in the routes file and you could edit the credit card through a fields_for method in your edit view:
form_for #user do |f|
f.fields_for :credit_card do |ff|
ff.label :number
ff.text_field :number
end
f.submit
end
Does that help?
Since Formatting is not allowed in comments, I am making a answer for it.
Thanks #twmills for your answer,
I am also new to rails. I have a question, will it work in case where I have following relationship:
class User < ActiveRecord::Base
has_many :credit_cards, :dependent => :destroy
accepts_nested_attributes_for :credit_card
end
class CreditCards < ActiveRecord::Base
belongs_to :user
end
In above case, you can't create a CreditCard object unless you have parent user. Will f.fields_for :credit_card do |ff| also create an object of CraeditCard #user to f?
As per my understanding, this is not possible as how will be tell the view, which credit card to edit.
Secondly, On edit, this is fine but can I do something similar at the time of user creation. i.e. getting his credit card information at the time of user creation.