Rails 3 - Nested Resources Routing - One to One relationship - ruby-on-rails-3

Having some trouble with some nested resources routing. What I'm trying to do is link to a user's profile page for editing purposes. In my view it is written as:
<%= link_to "Edit Profile", edit_user_profile_path(current_user) %>
Which errors out with:
No route matches {:action=>"edit", :controller=>"profiles", :user_id=>#<User id: 1, email: "EDITEDOUT", hashed_password: "EDITEDOUT", created_at: "2011-01-20 18:30:44", updated_at: "2011-01-20 18:30:44">}
In my routes.rb file, it looks like so:
resources :users do
resources :profiles, :controller => "profiles"
end
I checked my Rake routes, and it gave me this as a valid option:
edit_user_profile GET /users/:user_id/profiles/:id/edit(.:format) {:action=>"edit", :controller=>"profiles"}
Which I am able to manually navigate to. For good measures, here's proof of my controller:
class ProfilesController < ApplicationController
def edit
#user = current_user
#profile = current_user.profile
end
def update
#user = current_user
#profile = current_user.profile
respond_to do |format|
if #profile.update_attributes(params[:profile])
format.html { redirect_to(orders_path, :notice => "Your profile has been updated.") }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #profile.errors, :status => :unprocessable_entity }
end
end
end
end
Anyway, I've been having some problem tracking this down. Any pointers would help. For my DB design Profiles belong to Users in a one-to-one relationship. I'm hoping it's just something newbish I'm not noticing a new set of eyes might help.

If you look closely at your route, you'll see that it expects both a :user_id and an :id. The latter, in this case, refers to the user profile.
In order to tell Rails that you want that particular profile, you'll have to specify both the user and the profile in your link, like this:
edit_user_profile_path(current_user, #profile)
Now, Rails will use the first argument (current_user) for the :user_id part of the route, and the second argument (#profile) for the :id.

Related

Unpermitted parameters although controller has them whitelisted when creating user

In migrating a rails application from 3.2 to 4.1, I am hitting some issues with user creation. As there is a need to distinguish the current_user form a local_user. The controller create action
def create
#local_user = User.new(user_params)
respond_to do |format|
if #local_user.save
if params[:user][:avatar].present?
format.html { render :crop }
else
format.html { redirect_to(admin_user_path(#local_user), :notice => 'User was successfully created.') }
end
else
format.html { render :action => "new" }
end
Generates a console error: Unpermitted parameters: name, surname, pen_name[...], yet the User controller defines them:
def user_params
params.require(:user).permit(:name, :surname, :pen_name, [...])
end
The form call is:
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :method => :post, :validate => true) do |f| %>
This is necessarily a devise issue for a user can be created with the scaffolding for the User class with the exact same variables. There is some logic that devise is going through which does not pull all the controller logic ; what am I missing?
Needs a devise specific initializer, as per this demo, where all variables can be entered as an array.

CanCan Resource Conditions and special routing with friendly_id slugs

I have a Page Model that has a :name attribute. I have a specific route for the Page Model with the name "home", because I want this specific Page record to be found at the root_url. This works.. but because I'm hard coding the route... I only want users with the role "super_admin" to be able to change the :name attribute, on the Page model, where the name == "home". For example, users with the "admin" role should not be able to change the :name attribute on the "home" Page.
Can I get that fine grained with CanCan?
Should I put this logic in the PageControllers update action?
Should I set the "page#show" route differently (not hard code it)?
Not sure how to do any of these.
Thanks in advance for any advice!
ability.rb
elsif user.role == "admin"
can :manage, :all
cannot :update, Page, ["name == ?", "home"] do |page|
page.name == "home"
end
end
routes.rb (I'm using friendly_id to generate a slug from the :name attribute)
match '/:slug', :to => "pages#show", :as => :slug, :via => :get
root :to => 'pages', :controllers => "pages", :action => "show", :slug => "home"
pages_controller.rb (standard)
def update
#page = Page.find(params[:id])
respond_to do |format|
if #page.update_attributes(params[:page])
format.html { redirect_to #page, notice: 'Page was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #page.errors, status: :unprocessable_entity }
end
end
end
I must admit, I've read your question three times, and I think I have answers for you...
1 - Yes, I believe so. However, I'm not convinced your ability.rb code is correct. I'd aim for something closer to this:
cannot :update, Page do |page|
page.name == "home"
end
2 - If you do load_and_authorize_resource in your controller, that should be all you need, because that will load #page for you.
class PagesController < ApplicationController
load_and_authorize_resource
def update
respond_to do |format|
if #page.update_attributes(params[:page])
format.html { redirect_to #page, notice: 'Page was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #page.errors, status: :unprocessable_entity }
end
end
end
end
3 - To me, your route looks fine. That's likely the way I'd approach it.

Very strange routing error in rails 3

I got a controller called MeController. It has a bunch of actions like spaces and projects.
The spaces action does the following:
def spaces
#spaces = current_user.spaces
respond_to do |format|
format.html # show.html.erb
format.json { render json: #note }
end
end
The view just renders an other index template like:
<%= render :template => "spaces/index" %>
This works perfectly but now the stränge part begins... :S
This is the project action:
def projects
#projects = current_user.projects
respond_to do |format|
format.html # index.html.erb
format.json { render json: #projects }
end
end
The view renders also an index template:
<%= render :template => "projects/index" %>
But for the projects I get the following error:
Routing Error
No route matches {:action=>"edit", :controller=>"spaces", :id=>nil}
I just don't get why it should be an Routine Error with the action edit and the controller spaces. :/
Here are my routes:
# Profiles & Current User
resources :profiles
get "me" => "profiles#show", :as => "current_user"
get "me/spaces", :as => "current_user_spaces"
get "me/projects", :as => "current_user_projects"
get "me/tasks", :as => "current_user_tasks"
get "me/notes", :as => "current_user_notes"
get "me/discussions", :as => "current_user_discussions"
get "me/files", :as => "current_user_files"
# Permissions
resources :permissions
resources :spaces do
resources :projects do
resources :tasks
resources :notes
end
end
devise_for :users
root :to => redirect("/me/spaces")
Hope somebody has a hint for me! :)
So my guess would be:
In your template (projects/index), you are using url helpers like url_for or link_to with links to specific projects. The issue is that the projects have nested routing within your spaces resource. That's why you have to provide any url helper with a reference to both, space and project when you want it to generate an url to a project.
RoutingError is also thrown in case an url helper doesn't know how to construct an url.
This is a long shot, but I hope it helps.

Troubleshooting two-step nested model signup process

I want to initiate a sign-up process on my homepage. In the end, the process ideally would follow the following logic:
user = User.new
user.email = ""
user.password = ""
user.profile = Profile.new
user.profile.info = ""
user.profile.save
user.save
I'll be using nested model forms, of course. But is there a way to spread this into two parts? In part 1 the User would enter mainly user information, as well as a bit of profile information, and part 2 would contain solely 'profile' information. Then when all is said and done the user gets redirected to their user profile.
If this is possible, what is the general thinking on this type of process? Second, I'm wondering if someone can help me figure out how to achieve it. I have the nested model forms all set up but there must be something messed up in my routes.rb file/Controllers that is denying me the experience.
Here's my routes.rb file.
get "profiles/show"
get "/profiles/:id" => "profiles#show", :as => "profile"
post "/signup" => "profiles#create", :as => "signup"
get "skip/signup", :to => "users#newskip"
match "skip/profiles/new", :to => "profiles#newskip"
root :to => "users#new"
And here are my UsersController and ProfilesController respectively:
*class UsersController < ApplicationController*
before_filter :authenticate, :only => [:edit, :update]
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to signup_path, :notice => 'User successfully added.'
else
render :action => 'new'
end
end
*class ProfilesController < ApplicationController*
before_filter :authenticate, :only => [:edit, :update]
def new
#user.profile = Profile.new
end
def create
#profile = Profile.new(params[:profile])
if #profile.save
redirect_to profile_path(#profile), :notice => 'User successfully added.'
else
render :action => 'new'
end
end
Can anyone help show me the light? I know Devise is a solution but I'm trying to learn without that. At least at first. This previous question/answer looks like a potential starter.
Here is a Railscast about multistep forms. I think it should put you on track for what you're trying to accomplish.
I completed this by having user and profile create on the homepage, Profiles#edit as the second step, with a redirect_to profile.

How to create a custom POST Action in Rails3

I am trying to create a custom POST action for my article object.
In my routes.rb, I have set the action in the following way:
resources :articles do
member do
post 'update_assigned_video'
end
end
In my articles_controller.rb I have:
def update_assigned_video
#article = Articles.find(params[:id])
#video = Video.find(:id => params[:chosenVideo])
respond_to do |format|
if !#video.nil?
#article.video = #video
format.html { redirect_to(#article, :notice => t('article.updated')) }
else
format.html { render :action => "assign_video" }
end
end
Then in my view I make a form like this:
<%= form_for #article, :url => update_assigned_video_article_path(#article) do |f|%>
[...]
<%= f.submit t('general.save') %>
The view renders (so I think he knows the route). But clicking on the submit button brings the following error message:
No route matches "/articles/28/update_assigned_video"
rake routes knows it also:
update_assigned_video_article POST /articles/:id/update_assigned_video(.:format) {:action=>"update_assigned_video", :controller=>"articles"}
What am I doing wrong?
Is this the wrong approach to do this?
Your form_for will do a PUT request rather than a POST request, because it's acting on an existing object. I would recommend changing the line in your routes file from this:
post 'update_assigned_video'
To this:
put 'update_assigned_video'