Double controllers when using namespace in rails? - ruby-on-rails

I'm working on an application with a namespacing (admin section). Is there a DRY solution for not creating 2 controllers? Because I will need to create an public user controller and a admin user controller to manage the users.

How about inheriting the user controller? I use it myself (for images) and it suits me nicely:
# file: apps/controllers/images_controller.rb
class ImagesController < ApplicationController
# image code (to show the image for example)
end
# file: apps/controllers/admin/images_controller.rb
class Admin::ImagesCOntroller < ImagesController
# additional admin code (to delete the image for example)
end

You might consider rendering the page with optional "edit" buttons. For example, something like this:
Name: <%= #user.name %>
<% if #user.admin? %>
<% form_for #user do |f| %>
Editing stuff
<% end %>
<% end %>
That way, a user only sees it as a page, but an admin sees additional controls that allows them to edit the field. P.S. Make sure in your controller that you are checking to make sure it's an admin that is calling the update call.

Related

Getting 'form_for(#something)' to work outside of new.html.erb

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 %>

Rendering different views in one action

I want to have 2 kinds of views for the same posts in my rails application. For instance - in one where a logged in user can update and edit the post, and in the other any user can just view it and comment on it or select it.
How should I go about this? Do I need a separate class? I know I need a separate view for each, but how about the model and the controller?
1.case: your views are going to have similar content, but only the signed in users will have extra options like editing.
You should use a partial view and in your main view you should write something like this:
<% if signed_in? %>
<%= render 'edit_form' %>
<% end %>
Remember, the name of the partial should always start with a underscore, so your partial in this case would be called _edit_form.html.erb or _edit_form.html.haml, depending on what you are using.
2.case: depending on if the user is signed in or not, you want to render completely different views, then you should handle it in your controller:
def show
if signed_in?
render 'show_with_edit'
else
render 'show_without_edit`
end
end
And your files would be named show_with_edit.html.erb and show_without_edit.html.erb
Also, if your view for a signed in user was called show then you could just do this:
def show
render 'show_without_edit' unless signed_in?
end
3.case: if you want to change basically EVERYTHING depending if the user is signed in or not, you could create some custom methods and call them inside your original action like this:
def show
if singed_in?
show_signed_in
else
show_not_signed_in
end
end
private
def show_signed_in
# declaring some instance variables to use in the view..
render 'some_view'
end
def show_not_signed_in
# declaring some other instance variables to use in the view..
render 'some_other_view'
end

Redirecting to different actions without using a query string

I am trying to figure out the best way to do the following (there are a few ways I can think of, but I want to know what the best way to handle it is):
A user is putting together a shipment, and then clicks the "Send" link, which sends him to the /shipments/:id/confirm page. The confirm action checks to see if the user has a completed ShippingAddress; if not, it sends him to the ShippingAddress#new. (If he does, it render the confirm page.
I want the user to be able to complete the ShippingAddress#new page, submit it, and then be redirect back to the /shipments/:id/confirm. How can I do that? How can I pass the :id to the ShippingAddress#new page without doing something like redirect_to new_shipping_address_path(shipment_id: #shipment.id) in the Shipment#confirm action? Or is that the best way to do that?
class ShipmentsController < ApplicationController
def confirm
#shipment = Shipment.where(id: params[:id]).first
unless current_user.has_a_shipping_address?
# Trying to avoid having a query string, but right now would do the below:
# in reality, there's a bit more logic in my controller, handling the cases
# where i should redirect to the CardProfiles instead, or where I don't pass the
# shipment_id, and instead use the default shipment.
redirect_to new_shipping_address_path(shipment_id: #shipment.id)
end
end
end
class ShippingAddressesController < ApplicationController
def new
#shipment = Shipment.where(id: params[:shipment_id]).first
end
def create
#shipment = Shipment.where(id: params[:shipment_id]).first
redirect_to confirm_shipment_path(#shipment)
end
end
[In reality, there is also a CardProfiles#new page that needs to be filled out after the shipping address is].
Try calling render instead of redirect_to, and set the id into an instance variable. Adjust the view logic to pull that instance variable if it exists.
#shipment_id = #shipment.id
render new_shipping_address_path
In the view
<%= form_for #shipment_address do |f| %>
<% if #shipment_id %>
<%= hidden_field_tag :shipment_id, #shipment_id %>
<% end %>
I don't know your view logic entirely, but giving an example.

Where does the site-wide footer logic belong in a Rails 3 app?

I have a site-wide footer that should display a list of recent Users and Posts. I'm wondering where the logic should to gets this data. Should I have a "recent_users" method in the UsersController and a "recent_posts" method in the PostsController, or should I have a separate FooterController?
How about a _recent_users partial views/users and a _recent_posts partial in views/posts and have the footer partial render both of them?
All "business logic" should be put in the Model, not the controller. The query for recent Users and Posts should be in the User and Post model. Then, if you have a site-wide view element, move it into a partial and add that partial into the application.html.erb.
# User.rb
model User
def recent
# logic and query here
end
end
# Post.rb
(see above)
# application_controller.rb
before_filter :get_recent_posts
before_filter :get_recent_users
...
private
def get_recent_posts
#recent_posts = Post.recent
end
def get_recent_users
#recent_users = User.recent
end
# application.html.erb
...
<%= yield %>
...
<%= render :partial => 'layouts/footer', :locals => { :recent_users => #recent_users, :recent_posts => #recent_posts } %>
# layouts/_footer.html.erb
<% recent_users.each do |user| %>
<%= link_to user.name, user %>
<% end %>
# same for posts
A few important things to note:
don't access the instance variables (the #foo) in the partial... pass it into the locals hash and access it as a variable instead. It's just generally bad practice
you could also use a module
look into caching because you probably don't want to hit your database TWICE on every page load. You could use fragment caching on the footer and expire it every 15 minutes (probably the best option).

Rails 3, How to add an action for Projects

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.

Resources