简体   繁体   中英

Rails 4.0 multiple models and one controller

I'm in the process of learning Ruby on Rails, and now I have created the mobile version of my application.

I created the relation between models ans controller is one-one. Now I want to make changes to manage three models from one controller. I have read and watch videos a lot about how to do this but, it doesn't work when I try to do it in my application.

Models:

class Subject < ActiveRecord::Base
  has_many :pages

class Page < ActiveRecord::Base
  belongs_to :subject
  has_many :sections

class Section < ActiveRecord::Base
  belongs_to :page

Controller:

class SubjectsController < ApplicationController
  has_mobile_fu
  layout "admin"
  before_action :confirm_logged_in

  def index
    @subjects = Subject.newest_first
    @pages   = @subjects.pages.sorted
  end

This is the error:

NoMethodError (undefined method pages' for # <ActiveRecord::Relation::ActiveRecord_Relation_Subject:0x007fbbf3c9b218>): app/controllers/subjects_controller.rb:10:in index'

The application works well if I keep each model managed by its controller. The problem started now that I want to control multiple models from one controller.

Can definitely use multiple models in a single controller. The issue here is you're calling a method that doesnt exist for the active record relation.

An active record relation is typically a collection of returned objects from a query using active record. So the newest_first is returning multiple, not just one. If you want to get all pages for the subjects and sort them, you can do this:

@subjects = Subject.newest_first
@pages = @subjects.map(&:pages).flatten.sort { |a, b| a.title <=> b.title }

Can switch the attribute on which you wish to sort by. The map function goes through each one, and returns the object of which i passed in the symbol. It's a shortcut for:

@subjects.map { |subject| subject.pages }

The flatten then takes that array of active record relations and flattens it into a single array. I then just use the array sort.

Edit Here's a way you can do it using the database:

@subjects = Subject.newest_first
@pages = Page.where.not(:subject_id => nil).order(:title)

MVC

Something else you'll benefit from is to look at the MVC Programming Pattern :

在此处输入图片说明

Rails is famous for its strict coherence to the Model-View-Controller pattern, as it works like this:

  • You send a request to your app
  • Rails "routes" your request to a specific controller / action
  • The controller will then collate data from your Models
  • The controller will then render a view to display this data

The relationship between models and controllers is exclusive; meaning you don't have to call certain models from a controller, etc.

So the basic answer is no , you don't need to call a single model from a controller. However, you do need to ensure you have the correct model associations set up, as per the explanation below:


Associations

The caveat here, is that since Ruby is object-orientated (and Rails, by virtue of being built on Ruby, also being so), it's generally considered best practice to build your application around objects

"Objects" are basically elaborate variables (constructed from your Model classes), but the pattern behind making OOP work properly is super important - everything from Rails' routes to your controller actions are designed to be object-ORIENTATED

在此处输入图片说明

Each time you initiate an instance of a Model , Rails is actually building an object for you to use. This object allows you to call / use a series of attributes / methods for the object, allowing you to create the experience you require with Rails

--

The bottom line -

I would highly recommend examining the ActiveRecord Associations in your models (which will determine whether you need to call a single model or not):

#app/controllers/subjects_controller.rb
Class SubjectsController < ApplicationController
   def index
      @subjects = Subject.newest_first #-> good use of OOP
      @posts = # this is where your error occurs (`.posts` is only an attribute of each `Subject` object instance, which is fixed using the accepted answer)
   end
end

Hopefully this gives you some more ideas about how to construct Rails applications

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM