I'm using a tutorial to get a feel for ruby, I am very much a beginner. Before posting this I have spent a couple of hours trying to resolve this myself with no luck. Sorry in advance if my explanation isn't great:
So I am getting this error screen:
error message
I am following a tutorial to make a basic reddit style app and I am trying to add the comments functionality.
When you render a collection like render #comments, Rails will check the type name of the items in #comments (i.e. 'comment') then look for a partial under app/views/comments/_comment.html.erb by default (note the plural singular distinction between the partial name and the folder/collection name).
The following steps should resolve your issue:
Create a comments partial under:
app/views/comments/_comment.html.erb
Now, when you call render #comments, each item of your collection is passed to the partial as a local variable as the same name without the underscore:
In _comment.html.erb
<%# comment is defined because it matches the name of the partial %>
<%= comment.<some_attribute_on_comment> %>
Related
I am trying to challenge my learning by creating a simple project using rails forms, however I have gotten really stuck and can't find any information that seems to help online.
What I am trying to do:
I want to create a rails application with no model (so no persistence of data). Simply put I want a user to enter a Soundcloud URL which then gets transferred to the controller where I can do more logic. Essentially I am really trying to understand the connection between the Rails form and the controller in rails. I have spent all day reading about HTML forms, as well as googling this exact question without really fully getting it.
I understand there are different form helpers, but what I cannot seem to understand is how to use these without a model. My biggest hang up right now is I cannot get the form values transferred to the controller. I thought I understood RESTful routes, PUT/GET etc.. but this has made me super frustrated that I cannot seem to get my head around this. Any advice is super appreciated.
The code:
Below is the specific code I am struggling with, currently when I get submit the form it crashes giving me an error based on routes, and that's where I am stuck.
Problem code is found in the _form.html.erb file in views:
<%= form_tag '/show' do %>
<%= label_tag(:soundcloud_url, "Please enter a valid Soundcloud Artist URL:") %>
<%= text_field_tag(:soundcloud_url) %>
<%= submit_tag("Let's go!") %>
<% end %>
Routes.rb:
Rails.application.routes.draw do
resources :soundcloud_query
root 'soundcloud_query#index'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Error:
Routing Error
No route matches [POST] "/show"
rake routes output:
Prefix Verb URI Pattern Controller#Action
soundcloud_query_index GET /soundcloud_query(.:format) soundcloud_query#index
POST /soundcloud_query(.:format) soundcloud_query#create
new_soundcloud_query GET /soundcloud_query/new(.:format) soundcloud_query#new
edit_soundcloud_query GET /soundcloud_query/:id/edit(.:format) soundcloud_query#edit
soundcloud_query GET /soundcloud_query/:id(.:format) soundcloud_query#show
PATCH /soundcloud_query/:id(.:format) soundcloud_query#update
PUT /soundcloud_query/:id(.:format) soundcloud_query#update
DELETE /soundcloud_query/:id(.:format) soundcloud_query#destroy
root GET / soundcloud_query#index
Github link:
https://github.com/gaelant/simple_soundcloud_app/commit/09c4c4df524bb721a0f472b4378cd8c1ff18177f
Note: I understand this is a basic question but I have just gotten really confused with this. I know the way the code above is written is not correct, but I have tried so many different things and I just don't understand what is going on, or if this is even possible without a model.
Your /show form action points to nowhere. rails routes shows you which url is valid and to which controller#action each of them lead.
The correct form action would be
<%= form_tag '/soundcloud_query' do %>
<%= label_tag(:soundcloud_url, "Please enter a valid Soundcloud Artist URL:") %>
<%= text_field_tag(:soundcloud_url) %>
<%= submit_tag("Let's go!") %>
<% end %>
A far more better way is to use the url_helpers available through your defined ressource in Routes.rb
Doing so your form action would look like this
<%= form_tag soundcloud_query_index_path do %>
<%= label_tag(:soundcloud_url, "Please enter a valid Soundcloud Artist URL:") %>
<%= text_field_tag(:soundcloud_url) %>
<%= submit_tag("Let's go!") %>
<% end %>
The hardcoded and the url_helper based solution will route your request to a controller class named SoundcloudQuery where the action create will be called. Inside this action you have to put all needed logic.
It's also possible do define that /show should point to a specifc controller and action. This would look like this.
post '/show', to: 'mycontroller#myaction', as: 'mypathnameforhelper'
A much more better explanation with many examples about routes and how to use them can be found in this quite good guide.
Rails Routing from the Outside In
Hint: You should stay close to the ROR naming conventions. Controllers should have pluralized names. So you should define your routes like this:
Rails.application.routes.draw do
ressources :soundcloud_queries
root 'soundcloud_queries#index'
end
and then rename your controller class and file accordingly into SoundcloudQueries and soundcloud_queries.rb. But this is not mandatory.
I think in this case you should not use the url in the form_tag but the controller action.
Let's say you've got a view called my_form.html.erb and a submit_form method in your soundcloud_controller.rb
def submit_form
params[:soundcloud_url] your logic
end
I'd set up the routes like this:
get 'soundcloud_query' => 'soundcloud_query#my_form' // didn't want to use 'resources' but it doesn't matter
post 'soundcloud_query' => 'soundcloud_query#submit_form'
The form would then look like:
<%= form_for :this_doesnt_matter, action: :submit_form do |f| %>
<%= f.text_field :soundcloud_url %>
<%= f.submit %>
<% end %>
Im trying to render a collection of user inboxes:
<%= render current_user.my_inbox %>
It works fine with different views/controller except when i attempt to access the devise edit registration.
Missing partial devise/inboxes/_inbox
I notice that Devise is not looking at the right path. how do i tell devise that my inbox partial is located at inboxes/_inbox not devise/inboxes/_inbox
any suggestions will be greatly appreciated.
Assign the partial's name manually and pass along the data.
<%= render partial: "inboxes/inbox", collection: current_user.my_inbox %>
More info in the Rails Partial Docs (specifically passing variables to a given partial)
Somewhat new to rails, longtime programmer. I've got a question about views, controllers and partials really - wondering if I have this setup well.
I've got a pages controller, and on the index page (really the pages index method) I've got a partial in layouts called featured (ie app/views/layouts/_featured.html.erb) -- I've also got a Featured class. I would like basically the index of the featured class to be drawn here. But of course it's not working. SO the question is:
In the page itself I've got the <%= render 'features/index' %> which I'm beginning to think is the wrong way to go..
Do I axe this partial method and just call <%= render 'features/index' %> and let everything progress natively or
What would be the proper way of routing the featured collection to the partial? Since the controller is actually Pages it seems like I'm fighting against the tide.
<%= render 'features/index' %>
Doing this is wrong given your description. This will try to render a partial from app/views/features/_index.html.erb which you haven't mentioned.
To render the partial at app/views/layouts/_featured.html.erb you would do (perhaps a bit more verbose that is necessary)
<%= render partial: "layouts/featured" %>
The best suggestion I can offer is to pass a collection to this partial
<%= render partial: "layouts/featured", locals: { features: #features } %>
Since it seems your intention is for this partial to appear as a piece of a layout I will assume you wish for this partial to appear on multiple pages. This means on multiple actions you will need to have assigned the set of Feature instances this #features instance variable. One way to do this is a before_action.
before_action :setup_features
# ...
private
def setup_features
#features = Feature.all
end
A good place to start learning more about filters is in the Rails Guide
The partial at "app/view/layouts/_featured.html.erb" can only be rendered with
render 'featured'
and not 'featured/index'
render 'featured/index' will render "app/views/layouts/featured/_index.html.erb
Since the pages controller is really rendering the main index page in it's def index, all I had to do was #features = Feature.all and the variable is available for the partial pulled into the index page.
I need to get used to how simple rails is coming from other languages / frameworks.
UPDATE 3:
For anyone who reads this, this is why it wasn't working as expected in update 2 below: Passing a local variable to a partial that is rendered after the view has already loaded
If anyone knows how to solve that issue, let me know please.
UPDATE 2:
I updated the javascript with the quotation marks and it partially works...in the sense that the javascript is now functional and it will cause a string of text to appear on the page when I click the link as long as I have the partial only contain a string of text. However, when the partial includes the form fields code, something goes wrong.
If I just paste the following render code directly into the form in the new.html.erb view, it produces a new form section properly.
<%= render "add_round", f: f %>
However, when I try to include similar code in comps_helper.rb and then reference it from the link_to, it does not work:
In comps_helper.rb:
def addRound(f)
render "add_round", f: f
end
In new.html.erb:
<%= link_to "render it!", addRoundLink_path, remote: true %>
<div id="some_id"></div>
And I changed addRoundLink.js.erb to:
$("#some_id").html("<%=j addRound(f) %>"); #Is this the correct change to have made here?
Clicking the link_to link does nothing in that case.
Any thoughts?
UPDATED CODE:
Thanks for the reply. I've made the following changes and it still does not appear to be working. The link appears at the bottom of the form but when clicked does not change anything. What am I missing?
routes.rb:
resources :comps
match '/new_competition', :to => "comps#new"
get "/addRoundLink" => "comps#addRoundLink", :as => :addRoundLink
Note: I included the other 2 lines related to "comps" just in case those would cause an issue.
comps_controller.rb:
def addRoundLink
respond_to do |format|
format.js
end
end
comps_helper.rb:
def addRound
render "add_round"
end
addRoundLink.js.erb:
$("#some_id").html(<%=j addRound %>);
comps/new.html.erb:
<%= link_to "render it!", addRoundLink_path, remote: true %>
<div id="some_id"></div>
Thanks.
ORIGINAL QUESTION
First off, I'm new to rails. I've read and tried many solutions to similar questions but nothing has worked so far.
I created a form with rails form_for and fields_for. The form creates a new competition (comp). The competition has many rounds. The top half of the form (the form_for section) accepts the details about the competition as inputs and the bottom half of the form accepts details about each round (the fields_for section). The form works perfectly in this basic format.
I took all the code that is in the fields_for section and put it into a partial. My plan was to then create a "add new round" link to the bottom of the form that would simply display the partial above the link each time the link is pressed. This would add a new section to the form for a new round and allow the user to input as many rounds as they'd like. This is the part that I am struggling to make work.
I added this code to my comps_helper:
def addNewRound
render "add_round"
end
This renders the file /views/comps/_add_round.html.erb.
My question is: how do I get this to render in the form when a link is clicked. As far as I can get with the research I have done is:
<%= link_to "Add new round", { }, :remote => true %>
I don't exactly know what is supposed to go in the {} that will execute the addNewRound method. And I don't know what, if anything, I need to add to my comps_controller file.
Thanks so much for the help.
You have to create an action in your controller
app/controllers/some_controller.rb
def hello
respond_to do |format|
format.js
end
end
and define a route to this action.
routes.rb
get "/hello" => "some#hello", :as => :hello
then create a link to this action like that:
<%= link_to "render it!", hello_path, remote: true %>
<div id="some_id"></div>
When you click this link it will find its way to your action and respond with js(javascript) because we told action to respond with only js.
At the end render the partial to anywhere you want in your view(*in this example to the some_id div*)
app/views/some/hello.js.erb
$("#some_id").html("<%=j addNewRound %>");
WARNING: Creating dynamic forms is a pain. You will face a lot of problems (like setting different ids for new form elements etc...). I highly recommend you to use ryan bates nested_form gem
I'm very new to RoR, moving from PHP. I have what I hope is a simple question.
Say I have a Model called Article, stored in the table articles.
If I want to display a list of articles on several pages in my site, I might have some simple markup such as;
<% Article.find_each do |article| %>
<div class="article_list_wrapper">
<h1><%= article.title %></h1>
<p><%= article.body %></p>
</div>
<% end %>
Where would I put this markup? I mean in what file; if I put it in a view, then I will have to copy it if I want a similar list in a different part of the site.
Putting it in the Model itself seems intuitive to me, the Article object should know how to render itself, right? But that seems totally against the CMV idea.
And what if I wanted to have several ways of rendering the same object? Like a list view, a full page view etc.
Many thanks, just trying to get into the correct habits from the start.
You would put that portion of HTML markup into what is known as a partial -- something that can be rendered as a small piece of a larger layout. You're right, you wouldn't want to store the format in the model, because you might wish to render that specific HTML for web browsers and render very similar XML or JSON for clients using an API and render some other very similar content into ASN.1 or YAML for further other clients. The "view" really should stay associated with the views.
With this specific example, you would probably go one further and provide the articles to render via a variable rather than letting the view find the articles itself:
Controller:
def flubber:
#articles = Article.find_each(some_criteria)
end
View:
<div class="article_list_wrapper">
<%= render :partial => "article_list", :collection => #articles %>
</div>
And then provide a View for the corresponding controller with the name _article_list:
<h1><%= article.title %></h1>
<p><%= article.body %></p>
If the <div class="..."> is going to be identical in every single use of this partial, you could either pass a :template to the partial, or put it into a view helper, or put the entire render with the :template argument in a view helper. (Either the first or last approach here is what I'd do -- the <div class="..."> doesn't seem so important to require its own file, but if it were more complicated, it might -- and then I wouldn't want to give the partial :layout argument every time I needed it.)
MVC (Model-View-Controller):
The Model has (primarily) the database piece and business logic.
The Controller controls application flow.
The View shows the info, e.g. the browser view.
So the markup you show which has a bunch of HTML goes in the view.
That is app/models/views/article.rb
The Controller is the part that gets the info.
You should actually have #article = Article.all in your controller and then just use #article.each instead of Article.find_each in your view.
If you have conditions you can apply them directly on the Controller find but the better approach is to learn about how you can use model finders with scopes and then use those scopes from the controller. Always try and push things up from View to Controller to View and follow the 'fat Model, thin Controller' approach when practical.
For reuse partials can help but as better understanding of rails will help more.
See railscasts by Ryan Bates. Incredible tutorials.
You might also like my own bookmarks for rails at my (rails) linker app.
You can use partials for this.