Im using bootstrap & rails and have a user model and post model..users create posts (collections)..
with bootstrap in the navbar i want the user to be able to click a dropdown which displays the name's of their posts..i did this on one controller with a private method and a before_action but i don't want to do this for all the controllers and it didn't work for the application controller...
is there a better way to do this??
I was doing this
def list
#user = User.find_by_username(params[:id])
#collections = #user.collections
end
and a
before_action :list
at the top of the controller
What's the most semantic way to accomplish this??
If you could move both to your application controller, then it would be available to any controller. More generally, I'm not sure if this is the best approach to solve your problem.
These tips might also be useful.
Are you using devise? Or some other authentication plugin? If so you're likely going to have a current_user helper. This would allow you to simply do #collections = current_user.collections
To the extent possible, I recommend using more descriptive names for your actions and parameters. def fetch_list_collections might be a better name or instead of passing a param named id, perhaps your param should be named username. These naming conventions become extremely important both for others who might look at your code as well as for yourself if you return to it and are trying to remember what you wrote N months ago.
Your list action is generating a N+1 queries. Meaning that you're hitting the database multiple times when you should do so just once. See the rails guide on this. You might also look at ways to avoid this w/ devise. Devise is pretty well documented and I'll bet there is something in the wiki discussing this.
You may want to consider limiting when you call this action - at a minimum - a post request to an update action? What about before they've logged in? current_user might be nil and you'd have an error attempting to call a collections method on nil.
Take your time learning this stuff. You don't have to learn it all at once, but I thought the above might be helpful.
I got it to work with this in the application controller
before_action :list
private
def list
#collections = current_user.collections
end
thanks #arieljuod
Related
I've been racking my brain trying to figure out something that should be extremely simple, so I'm sure I'm just overlooking something and a fresh set of eyes might be useful since all my code is seemingly blurring together. I'm attempting to create vanity URLS for a site that allows users to create categories and then post relevant stories based on those categories. So, for example, I would like users to access /categories/movies in order to view the movie section. If I set it up to use the category id, /categories/1, it works no problem. For whatever reason, rails keeps trying to use the id parameter to find the category as opposed to the title parameter. I'm using Ruby 2.0.0 and Rails 4.0. I've read that the "find_by" method will become deprecated soon, so if there's a better way to handle this, that'd be great. Here's the relevant code:
Categories Controller
def show
#categories = Category.find_by_title(params[:title])
#category = Category.find_by_title(params[:title])
#posts = Post.where(category: set_category).all
end
Routes.rb
resources :categories
get "/categories/:title" => "categories#show"
Terminal readout when rendering page
Processing by CategoriesController#show as HTML
Parameters: {"id"=>"Movies"}
Just to reiterate, the parameters should read {"title"=>"Movies"} not id. Like I said, I'm sure it's something extremely simple that I've overlooked. Any help would be appreciated. Thanks.
I had to implement vanity urls as well and followed this blog post/tutorial
You pretty much create a slug in your model with the vanity-url, so
class Category < ActiveRecord::Base
def slug
title.downcase.gsub(" ", "-")
end
def to_param
"#{slug}"
end
end
Your show action in your controller would use the find_by_slug method
I think there is a gem that does this as well called friendly_id and here is a railscast but I have not personally used it
Hope this helps
ok, bear with me here, please.
i'm asking a question in which i'm not fully conversant of all the technical details, etc. (in other words, please take it easy on me for not being fully up on the par).
i've created a ROR application with Devise's gem ... it allows you to sign in, sign up, and log out.
it's very simple, and it just has a page in which you fill in your name, favorite hobby, & book. (hey, it's just an example)
i've also used their redirect code to go this page:
def after_sign_in_path_for(resource)
posts_path
end
the thing is that ... this page is public to everyone who logs in.
how do i redirect the user to their own page? and not see everyone's else "notes."
i've looked around ... and Devise has a link on sessions_controllers ...
do i use that? i don't fully understand the purpose of it.
if yes, how? still trying to figure out how all the puzzle pieces fit together, and it's hard to do that when you don't have full understanding of the topic itself.
or is there another way that's simpler?
if this question is too broad, please let me know ... but i'm not really quite sure how to break it down.
in essence, what i'm really asking is how do i have a user be directed to their own page and not see anyone else's page.
thanks in advance for any help/advice/pointers/etc.
First, let's assume your User model has_many :posts. In your PostsController index action (the default RESTful route would be posts_path) you can put something like this:
#posts = current_user.posts
and when visiting the index view you will only see the current user's posts.
That being said, you are not limited to the index view. You can customize any view you'd like and have a corresponding Controller action with declared instance variables which you can manipulate in your views.
Does that makes sense?
Try with:
def after_sign_in_path_for(user) # note: user or w/e your model is named
users_path(current_user)
end
Just to be educated I wanted to know if it is a good practice to have one controller method for both GET and POST actions, e.g def signup ... end, which would display a form and if request.post? is true - then perform all the business-logic and so on. Is it any good approach, or should I have these methods being separated from each other ?
Thanks in advice!
I think it'll be much better to define a separate action for the post request. You can obviously get it done within the same action, but if you're going to write a big if..else block in sign_up action you may as well use another action. You could call it create if you're short of names :P . It makes the code more logical and readable.
There is little difference in code organisation either way.
With separate methods, it looks like:
def signup_create
# create here
end
def signup_new
# render here
end
With the same method, it looks like:
def signup
if request.post?
# create here
else
# render here
end
end
It looks like they are both reasonably well organised. Choose what your prefer. If they are the default CRUD methods, separate methods are nice, given that there are separate names thought up already (eg. new vs create, edit vs update).
If they are not CRUD, or extra forms on the page, and you can only think of one name for it (like signup), feel free to overload the name and use the same method.
i think that separate actions for different requests are better if u are using(or going to use) method based authorization (eg cancan).
I am currentlly trying to design a RESTful MembershipsController. The controller action update is used only for promoting, banning, approving,... members. To invoke the update action the URL must contain a Parameter called type with the appropriate value.
I am not too sure if that is really RESTful design. Should I rather introduce sepearate actions for promoting,... members?
class MembershipsController < ApplicationController
def update
#membership= Membership.find params[:id]
if Membership.aasm_events.keys.include?(params[:type].to_sym) #[:ban, :promote,...]
#membership.send("#{params[:type]}!")
render :partial => 'update_membership'
end
end
end
Neither. The only "actions" a controller should handle are GET, PUT, POST, DELETE (+other http verbs). I realize posting this on a question tagged with "rails" is heresy but today I don't care.
One RESTful way to do this is to create new "processing resources" for each of these operations and POST the member to that resource to invoke the action.
When I say create a new resource, you can interpret that to mean, create a new controller.
To me this is one of the cases when you just shouldn't pull your hair out in efforts to adhere to REST conventions. Your model doesn't seem to fit in with the traditional CRUD concept, and the RESTful principle of differentiating actions via HTTP verbs doesn't seem to belong here too.
If I were you, I would split that action into separate actions for what you need to do with your memberships (trying to stay as DRY as possible). That would make the controller code more readable. And by creating some routes I would also make the view code cleaner (promote_membership_path, etc.). But that's just me :), so see what fits most for you.
EDIT:
here is an article which explains my point of view a bit: http://www.therailsway.com/2009/6/22/taking-things-too-far-rest
Well, there is more than one way to do things. The questions you should be asking yourself, is how many states are there? How often do new states get added? Etc.
If there wouldn't be that many states, I would create separate actions + a before filter for the find, but I think this is more of a personal preference. If you really want to keep it short, you can put each method on one line. So:
class MembershipsController < ApplicationController
before_filter :find_membership
def ban; #membership.ban!; render :partial => 'update_membership' end
def promote; #membership.promote!; render :partial => 'update_membership' end
protected
def find_membership
#membership = Membership.find(params[:id)
end
end
To answer your question whether it is RESTful: yes, your update method is perfectly RESTful, but remember that a PUT should be idempotent. So if I execute the same method twice, is the result the same? i.e. what happens if I ban a user and ban him again?
I'd like to do the following:
define a before_filter in application.rb that extracts the user's IP address and stores it anywhere, preferably in the session.
define two before filters in all my models as before_create and before_update that add the current user's IP to the object to be stored.
Problem: I cannot access session[] neither env[] in a model. Can anyone help with a standard solution that I don't know yet?
Regards
Jason
Try this. In your user model add a class attribute accessor
cattr_accessor :current_ip
In your application controller add:
before_filter :set_current_ip
protected
def set_current_ip
User.current_ip = request.env['REMOTE_ADDR']
end
Then in your model you should be able to just call User.current_ip
We do something similar to get the current_user object passed through.
You're having trouble doing what you want because Rails is designed not to allow you to have access to session information in your models. It's the classic separation of concerns with MVC. Models are meant to work independently of your other layers, and you'll be thankful they do when you start doing things with Rake or other system tasks where you won't have a session.
The
cattr_accessor :current_ip
is a horrible approach. It's a hack and it should be apparent why. Yes, it may work, but it's the wrong approach to this problem.
Since you're tracking "who" did "what" by their IP, the logical place for this to happen is in the controller layer. There are several approaches you can take, including using CacheSweepers as auditors, as outlined in the Rails Recipes book. CacheSweepers can observe models but also have access to all controller information. Using the ditry attributes in a rails model, you can see exactly what changed.
#user = User.find_by_login "bphogan"
#user.login = "Brian"
#user.save
#user.changed
=> ["login"]
#user.changes
=> {"login"=>["bphogan", "brian"]}
#user.login_was
=> "bphogan"
Combine this with the session info you have and you have a pretty awesome auditor.
Does that help?
If you want to save the IP in the session, you can create a before filter in the applicationController. Like this, for each action, the filter is called and the ip is stored.
authlogic is a plugin to manage users login/sessions etc, it has a built in option to track the users IP
What you really need is a versioning plugin - I suggest having a look at one of the fine solutions at http://ruby-toolbox.com/categories/activerecord_versioning.html
Edit: archived version of that link (was 404 since sometime in 2012): https://web.archive.org/web/20111004161536/http://ruby-toolbox.com:80/categories/activerecord_versioning.html