I am having a hard time solving this problem because this is my first time to learn ruby on rail, i have a index.html.erb, new.html.erb, show.html.erb, edit.html.erb files. So when i go to localhost:3000/blogs/edit page the page that is showing is show.html.erb and when i delete the show.html.erb then access the edit.html.erb im having a template missing error. but when i access localhost:3000/blogs/new or just localhost:3000/blogs its working fine.So here's my code inside blogs_controller.rb
class BlogsController < ApplicationController
def index
#content_first = 'This 1' ;
#content_two = 'This 2' ;
end
def new
end
def create
end
def edit
end
def update
end
def show
end
def destroy
end
end
I think your problem is that you're trying to access /blogs/edit , and the route is probably /blogs/edit/:id. As in you need to provide the id of a blog object, so that you can edit it.
If you run
rake routes
You will be able to see your available routes.
Hope this helps =)
Related
Using Devise I would like to display User account information such as profile name, first & last name etc on another page called profile page within my rails application.
I have created a controller called profiles with a view called profile/show
In the controller have added the below code
def show
#user = User.find_by_profile_name(params[:id])
if #user
render action: :show
else
render file: 'public/404', status: 404, formats: [:html]
end
end
end
In the view profiles/show I have the following code
<%= #user.profile_name %>
and the route is get 'profiles/show'.
My issue is when I do all of the above the profile name of the user still does not display on the profile page? There are no errors that come up it just doesn't display. I am not sure what code I am missing. I have checked the console and the user does have a profile name save to that ID and this is also in the devise account settings. So I am not sure how to get this information to display?
In Rails you would usually set it up like follow to take leverage of convention over configuration:
# config/routes.rb
resources :users, only: [:show, :index]
# app/models/user.rb
class User < ActiveRecord::Base
# ...
def self.find_by_uid!(uid)
User.find_by!("profile_name = :p OR id = :p", p: uid)
end
end
# app/controllers/users_controller.rb
class UsersController
# GET /users/:id
def show
#user = User.find_by_uid!(params[:id])
# Rails does the magic.
end
# GET /users
def index
#users = User.all
end
end
<%- # app/views/users/show.html.erb -%>
<h1><%= #user.profile_name %></h1>
The only special part here is that in the user model we create a class method which will query by id or profile_name. The reason that this is important is that it lets you use link_to(#user) and redirect_to(#user) as expected.
Which is also why we use resources :users. When the route name and the model line up the Rails polymorphic route handlers are able to do their job. If you want to use /profiles thats fine but never /profiles/show - including the action in the route defeats the whole purpose of REST.
The show action will render users/show.html.erb by default. So you rarely need to explicitly render in your controller.
render action: :foo
is only used when you want to render a template with the same name as another action, its usually used as follows:
def create
#something = Something.new
if #something.save
redirect_to(#something)
else
render action: :new # renders views/something/new.html.erb
end
end
If you want to explicitly render a template you would do render :foo or render "foo/bar".
And when you use find or find_by! it will raise an exception if the record is not found which by default will render the static 404 template. Reproducing this error handling in your actions is not very desirable since it violates the DRY pinciple.
Alright total noob, tried to find out what was happening but I haven't seen this come up with anyone else as far as I could find.
I'm going through a very basic blog tutorial with rails for the second time. made the home controller and the index view for it. all good. Next i made the 'posts' controller with basic classes and then views for index, edit, new, and show.
class PostsController < ApplicationController
def index
end
def new
end
def create
end
def edit
end
def update
end
def show
end
def destroy
end
end
The html for the views in their respective files
<h1>New Posts</h1>
<h1>Edit Posts</h1>
<h1>Show Posts</h1>
PROBLEM: In the browser when I go to localhost:3000/posts/edit it displays "Show Posts" instead of "Edit Posts". /show also displays "Show Posts". /new works fine and displays "New Posts".
I checked and it looks like localhost:3000/posts/literallyanything will display "Show posts".
I know this is potato level but I thought it was really odd and can't figure out why that would happen
Assuming you have a resource route for posts defined in your routing file like this:
resources :posts
you need to hit
localhost:3000/posts/<post id>/edit
More docs on routing here:
http://guides.rubyonrails.org/routing.html
You can always run rake:routes from your terminal to find out what route you need to hit for any given controller action.
My app allows users to log in and have sessions. I have a user controller and a sessions controller, mainly developed from railscasts "authorization from scratch".
I recently added the ability to upload files to S3 using a jquery uploader... Again lots of this comes from railscasts "uploading to amazon S3".
The problem is my uploads are not user specific. Right now my "upload" controller has an "authorize" before_filter to ensure you must be logged in to access the uploader; however once a user uploads a file, ALL users see the upload! Not good! I need to ensure users only see the respective files they upload.
I've tried a few things but none seem to work. I'm looking for some direction on how to ensure users only see the files they upload. I'm following different railscasts and rails documentation on nesting resources (I think that is how I have to do this?) but I keep missing something as there seems to be lots of changes that I don't 100% understand. I fix one error, then hit another, and am wondering if I'm even going down the right path or maybe I'm missing something?
The way I thought this should work is to first nest the resource:
resources :users do
resources :cust_uploads
end
Then I modified the models as below and ran "rake db:migrate" to tie them together... I may need to manually modify a migration file with a foreign id field?:
class User < ActiveRecord::Base
has_secure_password
attr_accessible :email, :password, :password_confirmation
validates_uniqueness_of :email
has_many :CustUploads
end
class CustUpload < ActiveRecord::Base
attr_accessible :cust_file_url, :name
before_create :default_name
belongs_to :User
def default_name
self.name ||= File.basename(cust_file_url, '.*').titleize if cust_file_url
end
end
This gives me tons of path errors which I'm fighting through now... as my new_cust_upload_path is probably something like new_user_cust_upload_path
I also think my forms and controllers need lots of modification....
I'm using form_for
<%= form_for(#cust_upload) do |f| %>
Which I think should now be #user.cust_upload?
controllers at the moment:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
session[:user_id] = #user.id
redirect_to root_url, notice: "Thank you for signing up!"
else
render "new"
end
end
end
class CustUploadsController < ApplicationController
before_filter :authorize
def index
#cust_uploads = CustUpload.all
end
def show
#cust_upload = CustUpload.find(params[:id])
end
def new
#cust_upload = CustUpload.new
end
def create
#cust_upload = CustUpload.create(params[:cust_upload])
end
def edit
#cust_upload = CustUpload.find(params[:id])
end
def update
#cust_upload = CustUpload.find(params[:id])
if #cust_upload.update_attributes(params[:cust_upload])
redirect_to #cust_upload_url, notice: "Cust upload was successfully updated."
else
render :edit
end
end
def destroy
#cust_upload = CustUpload.find(params[:id])
#cust_upload.destroy
redirect_to cust_uploads_url, notice: "Cust Upload was successfully destroyed"
end
end
Any direction will be greatly appreciated. I've been through many tutorials and can make simple things work from scratch, I just can't seem to integrate this functionality with my existing app. There is something here I can't wrap my brain around and I'm hoping someone can provide me with that Eurika moment! Thanks
EDIT
routes.rb and my models appear to have the appropriate connections (code below). When in terminal I type "rake routes" I get a list as expected (see below) however I get and error: "No route matches {:action=>"show", :controller=>"cust_uploads"}" for a link with user_cust_uploads_path. There is a show template in the cust_uploads path and rake routes says it exists! What am I missing?
user_cust_uploads GET /users/:user_id/cust_uploads(.:format) cust_uploads#index
POST /users/:user_id/cust_uploads(.:format) cust_uploads#create
new_user_cust_upload GET /users/:user_id/cust_uploads/new(.:format) cust_uploads#new
edit_user_cust_upload GET /users/:user_id/cust_uploads/:id/edit(.:format) cust_uploads#edit
user_cust_upload GET /users/:user_id/cust_uploads/:id(.:format) cust_uploads#show
Considering you want to achieve
Users who upload stuff should only see them.
Why don't you associate the uploads with a specific user id and then when showing them in the view pull them from their own id (current_user.uploads)
I am trying to set individual Meta Descriptions and Titles to individual pages in a Ruby on Rails App. It was a previous developers App, that I have been given the task to edit. Also, I am new to Rails and Ruby.
The app has a controllers/pages_controller.rb where I was am able to set unique variables for #descriptionX and #title on some pages (mission and disclaimer), but not for others, such as pet_planning.
class PagesController < ApplicationController
def index
#title = params[:page].humanize
render params[:page]
end
def pet_planning
#descriptionX = 'pet planning'
#title = 'pet planning title'
render :pet_planning
end
def mission
#title = 'Our Mission Statement'
#descriptionX = 'Mission Description'
render :mission
end
def disclaimer
#title = 'Our Disclaimer'
render :disclaimer
end
end
I think that the render params[:page] is where I am getting lost. I'm not 100% sure of what this is doing, or how to use it.
I don't understand why I would be able to control the #title and #description of mission but not pet_planning when their views are both in the same /views/pages/ directory. And I can't seem to find any distinction between the two anywhere else in the app.
Also, tried to add = #title = 'Pet Planning' in the /views/pages/pet_planning.html.haml file. It does change the title, however it also displays at the top of the page content unexpectedly.
Any help would be appreciate. Thanks.
I'd recommend having a read of the ActionController guide, which explains how Rails turns a request from the user into a page to render.
Basically, when you send a request, for example
GET http://www.example.com/pages/?page=pet_planning
then Rails works out what to do with it using the router (the routing guide explains this in more detail). I would imagine that your app is set up so that the /pages route matches to the PagesController#index action. You can have a look in your config/routes.rb file and/or type rake routes at the terminal to see how your routes are set up.
The bit after the question mark in the request is the "query string", and Rails turns this into a params hash which, for my example above, would look like {:page => "pet_planning"}. Your index action looks at that to get the name of the page to render - that's what render params[:page] is doing.
I guess that the reason you can modify the variables for some of your pages and not others is that some of them have their own routes - /pages/mission uses the PagesController#mission action, for example - while certain pages are accessed via the index action using the page param - /pages/?page=pet_planning or possibly /pages/index.html?page=pet_planning.
Update: Your existing route
match 'practice_areas/:page' => 'pages#index', :as => :pages
could be broken up into
match 'practice_areas/pet_planning' => 'pages#pet_planning' :as => :pet_planning
# etc ...
which would correspond to a controller that looks like this
class PagesController < ApplicationController
def pet_planning
#title = "Pet planning!"
#description = "Whatever..."
end
end
Your suggestion is close, but because the route format is "controller_name#action_name", you would require multiple controllers that looked like this
class PetPlanningController < ApplicationController
def index
#title = "Pet planning!"
#description = "..."
end
end
and you would have to move your views from app/views/pages/pet_planning.html.haml to app/views/pet_planning/index.html.haml. So it's probably not quite what you want.
Note that there might be a better way to tackle the problem than splitting everything up into separate actions, if all you are doing differently in each one is customising the title and description. For example, you could use a hash that maps your page name to its corresponding information:
class PagesController < ApplicationController
PAGE_INFO = {
"pet_planning" => ["Pet planning!", "Whatever..."],
"other_page" => ["Title", "Description"],
# ...
}
def index
page_name = params[:page]
#title, #description = PAGE_INFO[page_name]
render page_name
end
end
The render calls in pet_planning, mission, and disclaimer do the same as default behavior, so those calls can be removed. They are telling rails to use the pages with the given file names. For the index method, this is rendering a page based on a parameter.
The title and description are likely set in the layout. Look in /views/layouts/application.html.haml or /views/layouts/pages.html.haml.
I am trying to learn Ruby on Rails and trying to write some of the code by hand so that I learn how it works.
I made this tiny controller:
class TestsController < ApplicationController
def test
def show
render :text => "Hi from TestsController!"
end
end
end
and this is what is left of my view:
<h3> Hello test </h3>
and this is my routes.rb snippet:
resource :test
but it gives an error that: The action 'show' could not be found for TestsController
Thanks!
This is the output of rake routes:
home_index GET /home/index(.:format) home#index
root / home#index
test POST /test(.:format) tests#create
new_test GET /test/new(.:format) tests#new
edit_test GET /test/edit(.:format) tests#edit
GET /test(.:format) tests#show
PUT /test(.:format) tests#update
DELETE /test(.:format) tests#destroy
A basic controller looks like this:
class TestsController < ApplicationController
def show
end
end
You do not need the respond_to block if you only want to render the default view (in this case: app/views/tests/show.html.erb). The respond_to block is when you have some more advanced needs.
What #klump said is correct. Try running a basic scaffold. This will generate a controller, model and views for you. This generator is great when you are learning rails.
rails g scaffold Test
Also check out http://www.railsforzombies.com as it is a great way to learn rails.
You use respond_to when you want your action to respond to multiple formats. Client sets it's desired format in HTTP Accept header.
You can then specify different action for each format.
Example
def show
respond_to do |format|
format.html { Rails.logger.debug "rendering show.html" }
format.xml { Rails.logger.debug "rendering show.xml" }
format.js { Rails.logger.debug "rendering show.js" }
end
end
Refer to the API for more examples.