To generalize my problem, I am using an API that returns an iterable object. Within that those is an id for each object. My controller looks like this:
class SearchController < ApplicationController
def index
#search = API.find(params[:query])
end
end
My view is something like this:
<% #search.each do |thing| %>
<h2><%= thing.attr2 if thing.attr1 %></h2>
<%= API.list(thing.attr2) %>
<% end %>
I have tried adding a method into
class SearchController < ApplicationController
def index
#search = API.find(params[:query])
def getList(attr2)
API.list(thing.attr2)
end
end
end
and adding index and self before the definition (ex: self.getList(attr2)) and calling it in all those variations in the view:
<%= getList(thing.attr2) %>
I am wondering where I am going wrong here. I have additionally tried to add in the helper_method line as I read in a few docs but it would not recognize it. Also, would this be the correct way to go about this style-wise? Having a hard time finding references for it makes me think this isn't standard practice.
The method I was trying to make is a helper method, and therefore, needs to go in the helper method for the controller.
Related
I am using a namespaced Presenter object to help refactor some view presentation logic for my model attributes.
For one object being sent from the controller I would do
#user = Users::UserPresenter.new(#user)
and that works fine. For a query of users, I created a .present() method that maps and applies the UserPresenter.new to each user, so I do
#users = Users::UserPresenter.present(users)
and that works fine. But what about when I am passing an object that then iterates through a relationship in the view. A simple example would be
<% appointment.users.each do |user| %>
<% user = Users::UserPresenter.new(user) %>
<li> <%= user.age%></li>
<% end %>
A more complex example would be
<% appointment.appointment_host.family.users.each do |user| %>
<% user = Users::UserPresenter.new(user) %>
<li> <%= user.age%></li>
<% end %>
user_presenter.rb
module Users
class UserPresenter < SimpleDelegator
# methods
end
end
I don't like having to set the Presenter object in the view. What is a better way to handle this? Ideally using similar patterns as I have so far.
Perhaps you could create a hierarchy of presenters similar to model associations, and then pass only the root presenters to the view. Something like this:
class AppointmentPresenter
def initialize(appointment)
#appointment = appointment
end
def users
Users::UserPresenter.present(#appointment.users)
end
def host_family_users
Users::UserPresenter.present(#appointment.appointment_host.family.users)
end
# or perhaps even indeed create a presenter for each collection:
def appointment_host
AppointmentHostPresenter.new(#appointment.appointment_host)
# this presenter would have the `family` method returning a FamilyPresenter, etc.
end
end
I.e. some kind of "decorators" for the model associations, returning presenters instead of model objects.
I'm probably trying too hard for my first website but i wanted to make a dropdown on a (bootstrap) navbar to be flexible, and show the names of the saved work categories.
This is what i've tried to do in the application.html.erb file :
<ul class="dropdown-menu">
<% #workcategory.each do |workcategory| %>
<li><%= workcategory.name%></li>
<% end %>
Failed with error undefined methodeach' for nil:NilClasson the<% #workcategory.each do |workcategory| %>` line.
This is the workcategories controller :
class WorkcategoriesController < ApplicationController
before_action :find_workcategory, only: [:edit, :update, :destroy]
def index
#workcategories = Workcategory.all.order("created_at DESC")
end
def new
#workcategory = Workcategory.new
end
def create
#workcategory = Workcategory.new(post_params)
if #workcategory.save
flash[:notice] = "Workcategory created"
redirect_to(:action=>'index', :workcategory_id => #workcategory.id)
else
#workcategories = Workcategories.order()
render('new')
end
end
def edit
end
def update
end
def destroy
#workcategory.destroy
redirect_to workcategory_path
end
private
def find_workcategory
#workcategory=Workcategory.find(params[:id])
end
def post_params
params.require(:workcategory).permit(:name)
end
end
Any tips and help are welcome, even non-related to the initial question :) Thank you
If you want it in all ur actions, it is wise to put it in your application_controller.rb.
before_filter :set_work_categories
def set_work_categoriers
#w_categories = Workcategory.all.order("created_at DESC")
end
This should work fine.
Also, a tip.
You can use default_scope {order(created_at: :desc)} in your model WorkCategory.rb
Then you can use this like,
def set_work_categoriers
#w_categories = Workcategory.all
end
I would recommend changing the variable name to #w_categories or else it will conflict with your #work_categories name in index action.
In your application.html.erb file, change
<% unless #w_categories.nil? %>
<ul class="dropdown-menu">
<% #w_categories.each do |workcategory| %>
<li><%= workcategory.name%></li>
<% end %>
</ul>
<%end>
I guess this should do the trick
If we talk about index action, then you just forgot to use appropriate variable:
<ul class="dropdown-menu">
<% #workcategories.each do |workcategory| %>
<li><%= workcategory.name%></li>
<% end %>
Update
If you want to have this in all actions, then initialize #workcategories in before_action:
# your_controller.rb
before_action :initialize_work_categories
def initialize_work_categories
#workcategories = Workcategory.all.order("created_at DESC")
end
Layouts
application.html.erb is a layout, meaning that it will be present regardless of whether you're using the Workcategories controller or not.
If you want to load a variable into the layout, irrespective of which controller is being invoked, you'll need to make sure the #workcategory variable is present.
To do this, you would generally put the #workcategory declaration into the ApplicationController (which most other controllers inherit from):
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :set_categories
private
def set_categories
#workcategory = ....
end
end
This is the standard way to populate layout-side variables. It's not efficient and only works if your controllers inherit from the Application controller.
Some further pointers would include the following:
1. Object orientation
Ruby, and by virtue, Rails, is object orientated.
This means that everything you do should revolve around objects. This is why Rails has many helpers that seem to work "magically".
They're not magic at all - they just take the objects you pass them, and build pre-baked HTML to give you specific functionality.
A good example are the routes:
#config/routes.rb
resources :controller
The reason this is important is that when you call actions / variables, you need to think of them as objects. This is difficult to do for newbies, but if you can get your head around it, it helps your coding massively.
--
2. Controllers
Following on from the above, you have to remember that your controller is really just a way to manipulate objects.
Thus, if you're calling #workcategory, you need to appreciate where the object is going to come from and how it's going to be populated.
You can make a helper method work_categories and use that. Either define it directly in application_helper - or if you don't want to use helpers you can put this code in your ApplicationController
class ApplicationController < ActionController::Base
def work_categories
Workcategory.all.order("created_at DESC")
end
helper_method :work_categories
end
Then in your view:
<ul class="dropdown-menu">
<% work_categories.each do |workcategory| %>
<li><%= workcategory.name%></li>
<% end %>
</ul>
Hi everyone at this time I created a new controller, view and helper called Menuprestacionessociales
I have all the files as I think it should be
menuprestacionessociales_controller.rb
class MenuprestacionessocialesController < ApplicationController
def index
#variable = "cualquier contenido"
end
end
menuprestacionessociales/index.html.erb
<%= #variable %>
So I have a simple variable in my controller called #variable but if I try to show the content in the index, it doesn't show anything
Put <%= #variable %> somewhere in the index.html.erb file.
I want to place my <%= form_for(#something) do |f| %> which is currently located in app/views/something/new.html -- inside multiple pages, so maybe in app/views/layouts/application.html.erb
How do I get the #something variable and the form to work properly there, or somewhere else -- since it's defined in the controller #new action of SomethingController, it only seems to be available in the appropriate new.html.erb view..
You can put the form anywhere, just provide an instance variable of #something in controller
The basic usage is here.
ThisThingsController
def show
#this_thing = foo
#that_thing = bar
end
end
# View
<%= #this_thing %>
<%= form_for #that_thing %>
Of course you can use partial to render the form, as long as you feed it with variable it needs.
Try
<%= form_for SomeThing.new do |f| %>
Without fully understanding what you are trying to accomplish, I'll make this suggestion.
Add a before filter to your ApplicationController (alternatively you could create a module and mix it in where needed). Then call the before_filter when needed. This example will always run the before filter:
class ApplicationController
before_filter :set_something
private
def set_something
#something = ... # Fill in the logic here
end
end
Then add your form where needed. You can even make it appear conditionally depending on whether #something is set.
<% if #something %>
# Form goes here
<% end %>
I have a Project Index View that shows all the projects in an app
I want that view to show if the user signed in is a member or not....
In the Project Index View I have:
<% if teammember? %>
<td>Request to Join</td>
<% else %>
<td>Already Joined</td>
<% end %>
Then in the project's controller I have
def teammember(projectid)
do some stuff.....
end
But this gives me a "undefined method `teammember?"
You don't include the teammember method in the controller, you put that in the helper file (app/helpers/project_helper.rb)
module ProjectHelper
def team_member?(project_id)
# include other logic here
true
end
end
Then in any view that your Project controller renders, you can do:
<% if team_member?(project.id) %>
This is a team member.
<% else %>
This isn't a team member.
<% end %>
If this is a controller method that you need to access in the view, you can make it available like this:
class ProjectsController < ActionController::Base
helper_method :team_member?
end
This is essentially the same as if you had defined the method in helpers/projects_helper.rb
Just make sure you call the methods the same: your example shows one with a question mark, and one without.