Pass a table from controller to view - Rails - ruby-on-rails

In my Rails site, I have a model named Person, which has an ActionController and migration (database). I've inserted few rows to this table using the console (and saved them there!).
In the PersonController I have a method "list" which I want to list all the people which are in the database :
def list
#persons = Person.all
end
However, in the list.html.erb file in the person's view, I can't access this arrey. Trying to write something like :
<% #persons.each do |r| %>
raises an error claims that #person is nil.
I think I'm doing something wrong here. In conclusion, how can I pass a database from the controller to the view, and how can I disply it?
Thanks

The method you are using to transfer data from the controller to the view is appropriate. My guess is that Person.all is not returning any results, meaning your database is not being populated via the console. Try adding your data in via seeds.rb in the db directory, and then run rake db:seed. That should do it for you. Also, generally lists of models are run through the 'index' route. I would recommend using that instead of a route 'list'.
You can also check this post to make sure you are using the console correctly:
how to add data to database from rails console
*****************EDIT*******************
To use index to list display a list of a model, open your routes.rb file and add the people resource to generate all routes for the person model
resources :people
That will give you index, show, edit, create, update, and destroy routes (run rake routes to see a list of all the routes). If you do not want all of those, you can use only: and except: with the resource command to limit the routes created. Example
resources :people, only: index
You then need to update your controller to match each route that you want to use. So instead of 'list' you can use index, show, edit, update, create, and destroy.
def index
#people = Person.all
end
is an example of the index action definition. Then you just need a view to match the action, like index.html.erb. If you have any people in the database, they should now be in the #people variable during the index action and you can use that to list out each person. If you want to create some people to try it out, you can use the console, the show action you created using the resources command in the routes.rb, or use the seed.rb file and run rake db:seed.

Your variable in controller is #persons and not #person. The error you are getting is #person is nil. If that is not the problem, then please remember that rails uses singular for the model name, which is Person and plural in other cases, people in naming the tables and the controllers.
If this doesn't help, please post your real filenames, and your first line of the controller along with other relevant code.
Good luck!

Check the database and make sure the data is there. In addition, make sure you use Person.create and not Person.new when you are creating a record via the console.
Person.new must be assigned to a variable and save must be called on that variable. Create doesn't require that extra step
u = User.new(:first => "Chris", :last => "Tilley")
u.save! //required with new
u = Person.create(:first => "Chris", :last => "Tilley") //doesn't require save

Related

Accessing model in controller equals nil

I've got the following problem
I have a model called Article, which I access at two points.
First at the "home-page ( root )" I just do Article.all and list all of them.
That works fine for me, but whenever I access Article.all on my admin-panel ( /admin/articles ) it just says the following:
My controller looks like this:
def index
#news = Article.all
end
My model can be accessed easily in the rails console:
All of this is somehow solved by opening the controller and just re-saving it.
After a rails restart or logout and login on the site it is broken again
You may wish to organize groups of controllers under a namespace. Most commonly, you might group a number of administrative controllers under an
Admin:: namespace.
At the console:
namespace :admin do
resources :articles
end
This will create a number of routes for each of the articles
use one of the routes to access your controller from Admin
Try converting to array,
#news.to_a.count

How to display an specific item of database

My rails app has a database set.
def index
#clubs = Club.all
end
This is my controller.
If i type in my Index.html.erb
<% #clubs.each do |club| %>
<%= club.name %>
<% end %>
I get all the names of my database show in my index view.
What if I just want to pick one or just a couple?
Thru the rails console i can by typing c=Club.find(1) 1 by default takes id=1.
So how can i just display several ID's and not all one the database in the same index.html.erb.
thanks anyway!
Try this:
Let us consider that params[:ids] contains all the ids that belong to the records you want to get.
def index
#clubs = Club.where(id: params[:ids])
end
Fix
The straightforward answer here is to recommend you look at the ActiveRecord methods you can call in your controller; specifically .where:
#app/controllers/clubs_controller.rb
Class ClubsController < ApplicationController
def index
#clubs = Club.where column: "value"
end
end
This will populate the #clubs instance variable with only the records which match that particular condition. Remember, it's your Rails app, so you can do what you want with it.
Of course, it's recommended you stick with convention, but there's nothing stopping you populating specific data into your #clubs variable
--
RESTful
As someone mentioned, you shouldn't be including "filtered" records in an index action. Although I don't agree with this idea personally, the fact remains that Rails is designed to favour convention over configuration - meaning you should really leave the index action as showing all the records
You may wish to create a collection-specific action:
#config/routes.rb
resources :clubs do
collection do
get :best #-> domain.com/clubs/best
end
end
#app/controllers/clubs_controller.rb
Class ClubsController < ApplicationController
def best
#clubs = Club.where attribute: "value"
render "index"
end
end
There are several ways to select a specific record or group of records from the database. For example, you can get a single club with:
#club = Club.find(x)
where x is the id of the club. Then in your view (the .html.erb file), you can simply access the #club object's attributes.
You can also cast a wider net:
#disco_clubs = Club.where(type: "disco") # returns an ActiveRecord Relation
#disco_clubs = Club.where(type: "disco").to_a # returns an array
And then you can iterate over them in the same manner you do in your index.html.erb. Rails has a rich interface for querying the database. Check it out here.
Also note that individual records - such as those selected with the find method - are more commonly used with the show action, which is for displaying a single record. Of course, that's for generic CRUD applications. It't not a hard rule.
change
def index
#clubs = Club.all
end
to this
def index
#clubs = Club.find(insert_a_number_that_is_the_id_of_the_club_you_want)
end
Querying your database is a complex thing and gives you a ton of options so that you can get EXACTLY what you want and put it into your #clubs variable. I suggest reading this part of the rails guide
It should also be noted that if you're only going to query your database for one record then change #clubs to #club so you know what to expect.

Add new view to a controller in Rails

I have a controller, clients_controller, with corresponding index, show, edit, delete, new & form views. Is there a way to create a new view like clients/prospects.html.erb that acts the same way as clients/index.html.erb, except is routed at clients/prospects/?
I've tried this:
match '/clients/prospects' => 'clients#prospects'
And some other things in routes.rb, but of course get the error "Couldn't find Client with id=prospects".
The goal here is basically to have a prospects view and a clients view, and by simply switching the hidden field to a 1, it (in the user's mind) turns a prospect into a client (it's a CRM-like app).
There's a couple of things you need to do. First you need to put the your custom route before any generic route. Otherwise Rails assumes the word "prospects" is an id for the show action. Example:
get '/clients/prospects' => 'clients#prospects' # or match for older Rails versions
resources :clients
Also you need to copy / paste the index method in your ClientsController and name it prospects. Example:
class ClientsController < ApplicationController
def index
#clients = Client.where(prospect: false)
end
def prospects
#prospects = Client.where(prospect: true)
end
end
Lastly, you need to copy the index.html.erb view and name the copy prospects.html.erb. In the example above you would have to work with the #prospects instance variable.
Create a new action in clients controller named prospects. And then define a collection route in routes.rb for it as either resource full way. Or u directly use match as you were doing.
What you're doing is not wrong (although I'd change match to get, otherwise POST and DELETE requests to that url will also render your prospects view). Presumably you have
resources :clients
in your routes file? If so, what you have will probably work if you just move the line you quoted above the resources declaration -- the problem is that /clients/prospects matches the show route for the clients resource, so if it's defined first then that's the route that gets matched.
However, there's a more idiomatic way to define this route
resources :clients do
collection do
get :prospects
end
end
See Rails Routing documentation for more
Also see migu's answer for what else needs to be done once the url is being routed correctly (though there are other things you can do -- if you the two views are similar enough, you can reuse the view template, for example).

Trying to make urls of the form <base_url>/boards/<name> in ruby on rails and getting errors

I am using ruby on rails to make a simple social networking site that includes different message boards for each committee of a student group. I want the url structure for each board to look like https://<base_url>/boards/<committee_name> and this will bring the user to the message board for that committee.
My routes.rb file looks like:
resources :committees, only: [:index]
match '/boards/:name', to: 'committees#index(name)'
My index function of committees_controller.rb file looks like:
def index(name)
#posts = Committee.where(name: name)
end
And then I'll use the #posts variable on the page to display all of the posts, but right now when I navigate to https://<base_url>/boards/<committee_name> I get an Unknown Action error, and it says The action 'index(name)' could not be found for CommitteesController.
Could someone guide me through what I have done wrong?
Once I get this working, how would I make a view that reflects this url structure?
Set up your routes like this:
resources :committees, only: [:index]
match '/boards/:name', to: 'committees#show'
and the controller like this:
def index
#committees = Committee.all
end
def show
#committee = Committee.find_by_name!(params[:name])
end
You can't really pass arguments to controller actions the way you were trying to with index(name). Instead, you use the params hash that Rails provides you. The :name part of the route declaration tells Rails to put whatever matches there into params[:name].
You also should be using separate actions for the listing of committees and displaying single committees. Going by Rails conventions, these should be the index and show actions, respectively.
When routing, you only specify the method name, not the arguments:
match '/boards/:name', to: 'committees#show'
Generally you will declare something with resources or match but not both. To stay REST-ful, this should be the show method. Index is a collection method, usually not taking any sort of record identifier.
Arguments always come in via the params structure:
def show
#posts = Committee.where(name: params[:name])
end
Controller methods that are exposed via routes do not take arguments. You may construct private methods that do take arguments for other purposes.

Deleting all records in a database table

How do I delete all records in one of my database tables in a Ruby on Rails app?
If you are looking for a way to it without SQL you should be able to use delete_all.
Post.delete_all
or with a criteria
Post.delete_all "person_id = 5 AND (category = 'Something' OR category = 'Else')"
See here for more information.
The records are deleted without loading them first which makes it very fast but will break functionality like counter cache that depends on rails code to be executed upon deletion.
To delete via SQL
Item.delete_all # accepts optional conditions
To delete by calling each model's destroy method (expensive but ensures callbacks are called)
Item.destroy_all # accepts optional conditions
All here
if you want to completely empty the database and not just delete a model or models attached to it you can do:
rake db:purge
you can also do it on the test database
rake db:test:purge
If you mean delete every instance of all models, I would use
ActiveRecord::Base.connection.tables.map(&:classify)
.map{|name| name.constantize if Object.const_defined?(name)}
.compact.each(&:delete_all)
BlogPost.find_each(&:destroy)
If your model is called BlogPost, it would be:
BlogPost.all.map(&:destroy)
More recent answer in the case you want to delete every entries in every tables:
def reset
Rails.application.eager_load!
ActiveRecord::Base.descendants.each { |c| c.delete_all unless c == ActiveRecord::SchemaMigration }
end
More information about the eager_load here.
After calling it, we can access to all of the descendants of ActiveRecord::Base and we can apply a delete_all on all the models.
Note that we make sure not to clear the SchemaMigration table.
If you have model with relations, you need to destroy models that are related as well.
The fastest way to achieve this:-
Want to delete all data from the table
Post.delete_all
Want to delete specific data from the table, then the right way to do it is
Post.where(YOUR CONDITIONS).delete_all
# this above solution is working in Rails 5.2.1, delete_all don't expect any parameter
# you can let me know if this works in different versions.
# In the older version, you might need to do something like this:-
Post.delete_all "Your Conditions"
This way worked for me, added this route below in routes.rb
get 'del_all', to: 'items#del_all' # del_all is my custom action and items is it's controller
def del_all #action in ItemsController
if Item.any?
Item.destroy_all
redirect_to items_url, notice: "Items were destroyed."
else
redirect_to items_url, notice: "No item found here."
end
end
According to documentation:
2.5 Singular Resources - Sometimes, you have a resource that clients always look up without referencing an ID. For example, you would like /profile to always show the >profile of the currently logged in user. In this case, you can use a singular >resource to map /profile (rather than /profile/:id) to the show action: get 'profile', to: 'users#show'

Resources