I'm trying to wrap my head around Rails and have come into some difficulty trying to understand why somethings work and others do not
For example, having 2 tables:
Class User
table users
email:string
password:string
class Profile
table profiles
firstname:string
lastname:string
city:string
user_id:integer
Now each user should have 1 profile.
so in the module user.rb I have
has_one :profile
and in profile.rb
belongs_to :user
now all I want to do is show both tables in a table
<table>
<tr>
<th>User_ID</th>
<th>Email</th>
<th>Password digest</th>
<th>First Name</th>
<th>Last Name</th>
<th>City</th>
</tr>
<% #users.each do |user| %>
<tr>
<td><%= user.id %></td>
<td><%= user.email %></td>
<td><%= user.password %></td>
<td><%= user.profile.firstname %></td>%></td>
<td><%= user.profile.lastname %></td>%></td>
<td><%= user.profile.city %></td>%></td>
</tr>
<% end %>
</table>
I have a controller Show with an index page
def index
#this works
#users = User.all(:include => :profile)
end
This snippet of code I have found works, it displays the table properly.
But I have a list of other code that I've gathered/cobbled by trying to get this to work, that do not work.
So this list of codes would have been inside the def index individually tring to connect the two tables
#users = #users.build_profile()
Throws error: undefined method `build_profile' for nil:NilClass
#users = #users.profile
Throws error: undefined method `profile' for nil:NilClass
#users = #user.collect { |user| user.profile }
Throws error: undefined method `collect' for nil:NilClass
#users = Profile.find(:all)
Throws error: undefined method `email' for #Profile:0x46da5a0
<% #users.each do |user| %>
<tr>
<td><%= user.id %></td>
<td><%= user.email %></td>
<td><%= user.password %></td>
<td><%= user.proflie.firstname %></td>
#users = #profile.create_user()
Throws error: undefined method `create_user' for nil:NilClass
#users = #users.profiles
Throws error: undefined method `profiles' for nil:NilClass
#users = #user.each { |user| user.profiles }
Throws error: undefined method `each' for nil:NilClass
Why are all of these other ones failing, they seemed to work for other users that had similar problems (connecting two tables with a 1 to zero relationship)
The majority of the problems you are experiencing are caused just by the fact that you are calling methods on nil. You need to initialize the #users collection before you can call methods on it. Also make sure that you actually have some users in the database.
Getting all of the users:
#users = User.all(:include => :profile)
#users = User.includes(:profile) # I prefer this syntax
Building a profile. Note that you need to call this on one particular User, not on the collection given by the all method:
#profile = #users.first.build_profile # This won't actually save the profile
Getting the first user's profile
#profile = #users.first.profile
Getting all profiles:
#profiles = #users.collect { |user| user.profile }
Getting the first user's email:
#email = #users.first.profile.email
The rest is just a slightly modified version of the above.
Related
I'm coding a rails application to handle scheduling for university classes. Currently, I'm trying to make an index page to show all of the sections in the database, but I'm getting this error:
No route matches {:action=>"index", :controller=>"sections"}
However, when I look at my routes, I can see a controller action pair for section and index.
bin/rails routes
Prefix Verb URI Pattern Controller#Action
home_index GET /home/index(.:format) home#index
course_sections GET /courses/:course_id/sections(.:format) sections#index
POST /courses/:course_id/sections(.:format) sections#create
new_course_section GET /courses/:course_id/sections/new(.:format) sections#new
edit_course_section GET /courses/:course_id/sections/:id/edit(.:format) sections#edit
course_section GET /courses/:course_id/sections/:id(.:format) sections#show
PATCH /courses/:course_id/sections/:id(.:format) sections#update
PUT /courses/:course_id/sections/:id(.:format) sections#update
DELETE /courses/:course_id/sections/:id(.:format) sections#destroy
courses GET /courses(.:format) courses#index
POST /courses(.:format) courses#create
new_course GET /courses/new(.:format) courses#new
edit_course GET /courses/:id/edit(.:format) courses#edit
course GET /courses/:id(.:format) courses#show
PATCH /courses/:id(.:format) courses#update
PUT /courses/:id(.:format) courses#update
DELETE /courses/:id(.:format) courses#destroy
students GET /students(.:format) students#index
POST /students(.:format) students#create
new_student GET /students/new(.:format) students#new
edit_student GET /students/:id/edit(.:format) students#edit
student GET /students/:id(.:format) students#show
PATCH /students/:id(.:format) students#update
PUT /students/:id(.:format) students#update
DELETE /students/:id(.:format) students#destroy
root GET / home#index
rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show
rails_blob_representation GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show
rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show
update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update
rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create
Why does it not route correctly?
My section controller looks like this:
class SectionsController < ApplicationController
def index
#courses = Course.all
end
def create
#course = Course.find(params[:course_id])
#section = #course.sections.create(section_params)
end
def update
#course = Course.find(params[:course_id])
#section = #course.sections.find(params[:id])
#section.update(section_params)
end
def destroy
#course = Course.find(params[:course_id])
#section = #course.sections.find(params[:id])
#section.destroy
end
private
def section_params
params.require(:section).permit(:section_letter, :section_professor, :section_meetings, :section_capacity)
end
end
My index.html.erb view in the sections folder looks like this:
<h2>Sections</h2>
<table>
<tr>
<th>Number</th>
<th>Section</th>
<th>Name</th>
<th>Credit Hours</th>
<th>Professor</th>
<th>Meetings</th>
<th>Capacity</th>
</tr>
<% #courses.each do |course| %>
<% course.sections.each do |section| %>
<tr>
<td><%= course.course_num %></td>
<td><%= section.section_letter %></td>
<td><%= course.course_name %></td>
<td><%= course.course_credits %></td>
<td><%= section.section_professor %></td>
<td><%= section.section_meetings %></td>
<td><%= section.section_capacity %></td>
</tr>
<% end %>
<% end %>
</table>
And my routes file looks like:
Rails.application.routes.draw do
get 'home/index'
resources :courses do
resources :sections
end
resources :students
root 'home#index'
end
Any help is appreciated!
Its because the sections controller is a nested resource under the courses resource. There is a sections#index but it takes a :course_id parameter.
In other words there is no /sections path that directly maps to sections#index
If its a one-off endpoint you can declare this route
get 'sections' => 'sections#index', as: :sections
And you'd then need to update the #index method in the SectionsController and just pull all Sections like
#sections = Section.all
So I am trying to add the ability to select a user in the view, and then return only the Lists that are associated with that user. I can do this for now hard coded in the controller.
def show
#some_lists = List.sort(:boolean => true, :user_id => 3)
respond_to do |format|
format.html # show.html.erb
format.json { render json: #some_list }
end
end
But I want to be able to choose the user from the views
<% #some_lists.each do |list| %>
<tr>
<td><%= list.id_name %></td>
<td><%= list.day %></td>
<td><%= list.start_time %></td>
<td><%= list.end_time %></td>
</tr>
<% end %>
What is the best way to go about doing this, I also plan on adding the ability to sort by the list.start_time and list.end_time as well
You'll definitely want to do this with AJAX. For the specific thing you want to do (filtering/sorting a table) there's a javascript plugin I would recommend:
DataTables
(you'll want to check out the documentation on server-side processing)
There's even a really nice tutorial to using it with rails in RailsCast #340
I am working with the GoCardless API in my Rails 3 application. I have a subscription model which has a resource_id column which matches the id of the remote record.
I am trying to get extra information for a local subscription record from the API.
Subscription Index View
<% #subscriptions.each do |subscription| %>
<tr>
<td><%= subscription.resource_id %></td>
<td><%= subscription.resource_type %></td>
<td><%= subscription.signature %></td>
<td><%= subscription.state %></td>
<td><%= #gocardless.next_interval_start %></td>
<td><%= link_to 'Show', subscription %></td>
<td><%= link_to 'Edit', edit_subscription_path(subscription) %></td>
<td><%= link_to 'Destroy', subscription, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
Subscription Controller
def index
#subscriptions = Subscription.all
#gocardless = GoCardless::Merchant.find("XXXXXXXXXX").subscriptions
respond_to do |format|
format.html # index.html.erb
format.json { render json: #subscriptions }
end
end
As you can see I'm using the following line to retrieve the next interval start date
<%= #gocardless.next_interval_start %>
This doesn't work and returns nil. However, if I change it to the following all records show the value from the first record from the API.
<%= #gocardless.first.next_interval_start %>
According to the GoCardless API documentation you can lookup a subscription using the following:
GoCardless::Subscription.find("XXXXXXXXXX") # => #<GoCardless::Subscription ...>
So, my question. How do I pass the current subscription resource_id to the API so that I can view the next_internal_start value for each of the local subscription records?
Update
Using Adam's example below I get a 404 response from GoCardless. I think it's due to me not setting the merchant ID in the request. When I change the method to:
def gc_subscription
#gc_subscription ||= GoCardless::Merchant.find("MERCHANTID").subscriptions.find(self.resource_id)
end
I get undefined methodinterval' for #` for any attribute I try and request using the following code:
<% for subscription in #subscriptions %>
<%= subscription.gc_subscription.amount
<% end %>
When using the same code to get local content it works as expected:
<% for subscription in #subscriptions %>
<%= subscription.resource_id %>
<% end %>
I've checked that the value I am trying to retrieve is available in the API. https://sandbox.gocardless.com/docs/api_guide#resources-available
Update Two
As before calling the first result works using Adam's method:
<%= subscription.gc_subscription.first.amount %>
This returns 2.5 which is the value of the first subscription.
If I had a local Subscription model which linked to a remote data source I would have a method like this on my Subscription model which provided access to the remote object:
def gc_subscription
#gc_subscription ||= GoCardless::Subscription.find(self.resource_id)
end
Then you can access this method as necessary without any need for any GC logic in the view or controller. For example:
for subscription in #subscriptions
subscription.gc_subscription.some_method #=> "output"
end
Or, if you are only working with one subscription:
subscription = Subscription.find(id)
subscription #=> Your local Subscription instance
subscription.gc_subscription #=> GoCardless::Subscription instance
With it configured like that, you will be able to remove the #gocardless from your controller and replace your view with this:
<% #subscriptions.each do |subscription| %>
<tr>
<td><%= subscription.resource_id %></td>
<td><%= subscription.resource_type %></td>
<td><%= subscription.signature %></td>
<td><%= subscription.state %></td>
<td><%= subscription.gc_subscription.next_interval_start %></td>
<td><%= link_to 'Show', subscription %></td>
<td><%= link_to 'Edit', edit_subscription_path(subscription) %></td>
<td><%= link_to 'Destroy', subscription, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
I hope that helps.
I have a post model and an upvote model.
upvote.rb
class Upvote < ActiveRecord::Base
has_one :user
belongs_to :post
end
# == Schema Information
#
# Table name: upvotes
#
# id :integer not null, primary key
# user_id :integer
# post_id :integer
# comment :text
# created_at :datetime
# updated_at :datetime
#
Now within posts/index I want to add an upvote for the current user and the post.
Some research pointed me to write a helper
posts_helper.rb
module PostsHelper
def upvote_post(post)
#upvote = Upvote.new
#upvote.user_id = current_user.id
#upvote.post_id = post.id
if #upvote.save
flash.now[:notice] = 'Upvote was successfully created.'
end
end
end
Inside my view I want to call the helper only on clicking a link but can't seem to get link_to working properly.
<% #posts.each do |post| %>
<tr>
<td><%= link_to "upboats" upvote_post(post) %></td>
<td><%= post.name %></td>
...
I get the error syntax error, unexpected tIDENTIFIER, expecting ')' and can't seem to find any good alternatives.
What am I missing here?
UPDATED
It was a comma. facepalm
Plenty of other issues, but that was what led to the error.
<% #posts.each do |post| %>
<tr>
<td><%= link_to "upboats", upvote_post(post) %></td>
<td><%= post.name %></td>
...
Closing open question.
It was a comma.
UPDATED
It was a comma. facepalm
Plenty of other issues, but that was what led to the error.
<% #posts.each do |post| %>
<tr>
<td><%= link_to "upboats", upvote_post(post) %></td>
<td><%= post.name %></td>
...
i have this in the controller
#ads = Ad.all(:joins => 'LEFT JOIN states ON ads.state_id = states.id')
but i have problem to query field of states table.
any idea?
<% #ads.each do |ad| %>
<tr>
<td><%= ad.title %></td> <- title is ad field.no problem
<td><%= ad.name %></td> <- name is states field.problem at here
</tr>
<% end %>
I don't think this will work unless you have associations set up. Unless performance is a concern, you may just want to use the association without joins
ad.rb
class Ad < ActiveRecord::Base
belongs_to :state
end
state.rb
class State < ActiveRecord::Base
has_many :ads
end
controller
#ads = Ad.all
view
<% #ads.each do |ad| %>
<tr>
<td><%= ad.title %></td>
<td>
<%= ad.state.name %>
</td>
</tr>
<% end %>
I think you need to put this: ads.state_id = states.id like this: #{ads.state_id = states.id}
The #{ } will evaluate the ruby code inside. Otherwise what you have is just text inside a string.
I'm not quite sure what your issue is, though, so I'm not totally sure that will fix it.