How to access certain database tables in Rails controller? - ruby-on-rails

I am using Rails as a JSON API. My database has the following structure: the City model has_many Users, which in turn has_many Businesses.
When I send a GET request to businesses#index, I want Rails to return all the businesses in a given city, not just for a given user. What's the best way to do this?
I've already tried the given code below as a first pass, which is returning an internal server error (500).
def index
#city = City.find(params[:city_id])
#users = #city.users
#businesses = #users.businesses
render json: #businesses
end

Can you try this?
Because of the #user is an array. so the error will occuring.
# city.rb
class City < ApplicationRecord
has_many :users
end
#user.rb
class User < ApplicationRecord
belongs_to :invoice
has_many :businesses
end
#business.rb
class Business < ApplicationRecord
belongs_to :user
end
# your controller
def get_business
#city = City.find(params[:id])
#business = #city.users.includes(:business)
render json: #business
end

Add a new relationship to your City model:
has_many businesses, through: users
Then when you have a specific city you can get all businesses:
#city.businesses

You might also want to try starting with the Business model to make the query.
Business.joins(user: :city).where(cities: { id: params[:city_id] })
joins uses the association names
where uses the table names

Related

Rails replace simple ActiveRecord relation in case of big amount of data

In my app controller looks pretty simple:
class ProductsController
before_action :set_company
def index
#products = company.products.includes(:shipment)
end
private
def set_company
#company = Company.find(params[:company_id])
end
end
But what I worry about is the #product inside Index action was properly declared? What if I'll have millions of products? is there more efficient solution?
Model relations below:
class Products < ApplicationRecord
belongs_to :company
has_many :shipment
end
class Company < ApplicationRecord
has_many :products
end
class Shipment < ApplicationRecord
belongs_to :products
end
There is definitely a problem if you have million of records because your query is going to be too big, in this case you can add pagination in any flavor or use any other strategy that reduce the number of records queried each time.
To do pagination in Rails you can use https://github.com/kaminari/kaminari but this is not the only strategy available to do this.

Event Registration Form

newbie here...
I am trying to create an events registration page where anybody can register for an event without logging into the system.
My problem is trying to figure out how to tie the registration info to the specific event. I've created all the associations but can't figure how to tell the db that the person is registering for a specific event.
Here are my associations:
class Event < ActiveRecord::Base
belongs_to :user
has_many :event_regs
has_many :regs, through: :event_regs
class Reg < ActiveRecord::Base
has_many :event_regs
class Reg < ActiveRecord::Base
has_many :event_regs
Thanks in advance
Newbie here
Welcome!
Here's what you'll need:
#app/models/event.rb
class Event < ActiveRecord::Base
has_many :registrations
end
#app/models/registration.rb
class Registration < ActiveRecord::Base
belongs_to :event
end
This will allow you to use the following:
#config/routes.rb
resources :events do #-> url.com/events/:id
resources :registrations #-> url.com/events/:event_id/registrations/
end
#app/controllers/registrations_controller.rb
class RegistrationsController < ApplicationController
def new
#event = Event.find params[:event_id]
#registration = #event.registration.new
end
def create
#event = Event.find params[:event_id]
#registration = #event.registration.new registration_params
end
private
def registration_params
params.require(:registration).permit(:all, :your, :params)
end
end
This will create a new registration record in your db, associating it with the Event record you've accessed through the route.
--
From this setup, you'll be able to use the following:
#app/controllers/events_controller.rb
class EventsController < ApplicationController
def show
#event = Event.find params[:id]
end
end
#app/views/events/show.html.erb
<% #event.registrations.each do |registration| %>
# -> output registration object here
<% end %>
Foreign Keys
In order to understand how this works, you'll be best looking at something called foreign keys...
This is a relational database principle which allows you to associate two or more records in different database tables.
Since Rails is designed to work with relational databases, each association you use will require the use of a "foreign key" in some respect.
In your case, I would recommend using a has_many/belongs_to relationship:
You'll need to make sure you add the event_id column to your registrations database.

accessing associations within before_add callback in Rails 3

In Rails 3.2 I have been looking for a way to traverse the associations of an object within the before_add callback.
So basically my use case is:
class User < ActiveRecord::Base
has_and_belongs_to_many :meetings
end
class Meeting < ActiveRecord::Base
has_and_belongs_to_many :users
has_many :comments, :before_add => :set_owner_id
end
class Comment < ActiveRecord::Base
belongs_to :meeting
end
def set_owner_id(child)
child.owner_id = <<<THE USER ID for #user >>>
end
and I am creating a comment within the context of a user:
#user.meetings.first.comments.create
How do I traverse the associations from within the before_add callback to discover the id of #user? I want to set this at model level. I have been looking at proxy_association, but I may be missing something. Any ideas?
You should probably create the comment in the context of the meeting, no? Either way, you should handle this in the controller since you'll have no access to #user in your model.
#comment = Meeting.find(id).comments.create(owner_id: #user, ... )
But if you insist on your way, do this:
#comment = #user.meetings.first.comments.create(owner_id: #user.id)

Active Relation: Retrieving records through an association?

I have the following models:
class User < ActiveRecord::Base
has_many :survey_takings
end
class SurveyTaking < ActiveRecord::Base
belongs_to :survey
def self.surveys_taken # must return surveys, not survey_takings
where(:state => 'completed').map(&:survey)
end
def self.last_survey_taken
surveys_taken.maximum(:position) # that's Survey#position
end
end
The goal is to be able to call #user.survey_takings.last_survey_taken from a controller. (That's contrived, but go with it; the general goal is to be able to call class methods on #user.survey_takings that can use relations on the associated surveys.)
In its current form, this code won't work; surveys_taken collapses the ActiveRelation into an array when I call .map(&:survey). Is there some way to instead return a relation for all the joined surveys? I can't just do this:
def self.surveys_taken
Survey.join(:survey_takings).where("survey_takings.state = 'completed'")
end
because #user.survey_takings.surveys_taken would join all the completed survey_takings, not just the completed survey_takings for #user.
I guess what I want is the equivalent of
class User < ActiveRecord::Base
has_many :survey_takings
has_many :surveys_taken, :through => :survey_takings, :source => :surveys
end
but I can't access that surveys_taken association from SurveyTaking.last_survey_taken.
If I'm understanding correctly you want to find completed surveys by a certain user? If so you can do:
Survey.join(:survey_takings).where("survey_takings.state = 'completed'", :user => #user)
Also it looks like instead of:
def self.surveys_taken
where(:state => 'completed').map(&:survey)
end
You may want to use scopes:
scope :surveys_taken, where(:state => 'completed')
I think what I'm looking for is this:
class SurveyTaking < ActiveRecord::Base
def self.surveys_taken
Survey.joins(:survey_takings).where("survey_takings.state = 'completed'").merge(self.scoped)
end
end
This way, SurveyTaking.surveys_taken returns surveys taken by anyone, but #user.survey_takings.surveys_taken returns surveys taken by #user. The key is merge(self.scoped).
Waiting for further comments before I accept..

How to call a variable through the find method

I'm new to ruby on rails and here is the problem:
I'm trying to get the client name inside a loop about the car information. The car data holds an column called "belongs_to" which is the ID of the client.
The important line: <td><%= #client.find(car.belongs_to) %></td>
The controller:
def index
#cars = Car.all
#client = Client.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #cars }
end
end
How would you guys do this?
You would use Models to achieve this:
class Car < ActiveRecord::Base
belongs_to :client
end
class Client < ActiveRecord::Base
has_many :cars
end
and in your View:
#car.client
EDIT
or the other way round:
#client.cars
# to iterate over them:
#client.cars.each do |car|
# do something with car
end
belongs_to is not a very good column name. There is an association type called "belongs_to" where you can establish a relationship between models, where one of them "belongs_to" another model, such as:
class Car < ActiveRecord::Base
belongs_to :client # there is a column on the cars table called "client_id"
end
and
class Client < ActiveRecord::Base
has_many :cars
end
Then you can do:
client = car.client
Take a look at Ruby on Rails Guides - A Guide to Active Record Associations
Try
Client.find(car.belongs_to)
What you really want to do, though is have your Car model have something like this
belongs_to :client
And your Client model have
has_many :cars
Then you can simply call #car.client to get what you want.
I guess you could do something like:
#cars.each do |car|
car.client
end
and in car model, I guess you alredy have:
belongs_to :client

Resources