Link to a slug for a resource - phoenix-framework

I have a Country:
mix phx.gen.html Location Country countries name slug:unique
For linking to a Country I'd like to use the slug and not the id. How can I achieve it that this code will link to the slug (e.g. http://localhost:4000/countries/germany)?
<%= link "Show", to: country_path(#conn, :show, country), class: "btn btn-default btn-xs" %>

You need to implement the Phoenix.Param protocol for the module. The easiest way to do this is to add the following before the schema "..." in your module:
#derive {Phoenix.Param, key: :slug}
schema "..." do
...
end
Now instead of id, the slug field will be used when generating links from the URL helpers generated by Phoenix.

Related

How to create nested model from partial Rails 6

Newbie Here!
I'm unsuccessfully trying to submit a form of a nested model.
Aim:
Verify a translation by submitting a boolean to a reviews model to associate whether a translation is verified or not, with translation entry and user model associated references.
# routes.rb
resources :entries do
resources :reviews
end
# entry.rb
belongs_to :user
has_one :review
accepts_nested_attributes_for :review
# user.rb
has_many :entries
has_many :reviews
# review.rb
belongs_to :user
belongs_to :entry
From entry index, pass the entry instance to partial, works perfect
# /entries/index.html.erb
<% #entries.each do |entry| %>
...
<%= render 'reviews/new', entry: entry %>
...
<% end %>
Unsuccessfully setting up new/create form.
What happens is that the entry instance is well received, but I am failing to create a new model instance for review belonging to entry.
entry.review raises an nil error for review, while entry is fine when testing through browser console
First argument in form cannot contain nil or be empty
# reviews/_new.html.erb
<span>
<%= form_for entry.review do |f| %>
<div class="form-check form-switch">
<%= f.check_box :verified, class: "form-check-input" %>
</div>
<%= f.submit class: "btn btn-primary"%>
<% end %>
</span>
Another attempt was also to use just #review from the controller but that doesn't obey nested routes.
My controller looks like this
# reviews_controller.rb
def create
#entry = Entry.find(params[:entry_id])
#review = #entry.review.build(review_params)
#review.user_id = current_user.id
#review.save
end
private
def review_params
params.require(:review).permit(:verified, user: current_user, entry: #entry)
end
Am I suppose to implement my actions in the entries_controller?
I have also found the tutorial here useful but replication was unsuccessful.
Another StackOverflow reference here
I still get the error entry.review.build that review is nil.
First argument in form cannot contain nil or be empty
When building an associated record over a has_one relation, instead of
#review = entry.review.build(review_params)
you need to use the following:
#review = entry.build_review(review_params)
See the documentation for more details.
Am I suppose to implement my actions in the entries_controller?
It depends on what you're after. If you have a dedicated form for adding a new review and it is not embedded in another form for creating or updating an entry then implementing a create action in ReviewsController is the straightforward solution – in this case you should also not need accepts_nested_attributes_for in Entry.
If, however, you want to be able to create or update an entry as well as its review using the same form, then you should nest the review form in the form of the entry, keep accepts_nested_attributes_for, and use actions in EntriesController. The documentation should get you started there.

Reading Rails database values from a URL

In my ruby on rails project, I have a share model which stores share basic values like share name, market cap, current value, book value etc. In rails, when I want to create a new share record, instead of user entering the details, I want them to enter a URL from a financial website and I want my code to read the share basic parameters from the financial website. URL is not stored in the database.
for example: If the user enters http://www.moneycontrol.com/india/stockpricequote/food-processing/nestleindia/NI. My code should read below parameters and store it in database.
name: Nestle , price: 5628, market cap: 54,366.89, book value: 352.69 etc
I read webpages using Nokogiri. And since reading from web takes time, I have to use delayed_job as well.
My new.html.erb has only one input which is URL which sends a post request to "create" action. Now URL is not part of my model. I have declared a :url parameter inside the model as below:
class Share < ActiveRecord::Base
attr_accessor :url
end
Now I am bit confused as to how to handle this url in my model/controller. Which is the best place to implement URL reading method? is it controller or model?
If I pass the url to model, how to implement the method to get url and read the parameters?
If I read the parameters in controller, how do I pass them to model?
I am not able to access the url parameter inside my controller as well. When I call my method to readthe webpage, I get an error saying, empty url is passed:
My new.html.erb:
<%= form_for(#share) do |f| %>
<p>
<%= f.label :url %>
<%= f.text_field :url, autofocus: true %>
</p>
<p>
<%= f.submit 'Pull the data'%>
</p>
<% end %>
and my current create method in my controller:
def create
#url = params[:url]
#readShareBasic(url) is a method to read the website and return a hash
#share = Share.new(readShareBasic(url)).permit(:name, :current_price, :year_low, :year_high, :current_PE_ratio, :market_cap, :book_value, :description, :price_to_book_value))
redirect_to shares_url
end
Here in controller, I am not able to access the content of params[:url] either.
thanks in advance
Use the controller create method to get the url and create/save a new share instance. You don't need the accessor in the model. If you look in the source code of your form, you'll see how the form data is being passed.
In the controller, its better to separate the strong params into its own method.
def
#url = params[:share][:url]
#share = Share.new(share_params)
#share_details = readShareBasic(#url)
# assign values from readShareBasic to the share instance as needed
# save share
end
private
def share_params
params.require(:share).permit(:name, :current_price, :year_low, :year_high, :current_PE_ratio, :market_cap, :book_value, :description, :price_to_book_value, :url)
end

Is This a Bug? Can't Specify form id using form_for in Padrino

I have this form_for tag:
= form_for #food, :autocomplete => "off", :id => "food" do |f|
This is the tag it generates:
<form action-autocomplete="off" action-id="food" accept-charset="UTF-8" method="post">
How can I specify the html form id attribute from the form_for tag? Note that padrino has added an "action" before the autocomplete attribute as well.
This looks like a bug to me. I'm using version 0.12.2 of Padrino.
You need to specify the URL as the second parameter in case you want to use a custom id. The code should be:
= form_for #food, '/path/to/create/', id: 'food' do |f|
code for form_for
This is a similar pattern adopted from Rails. In Rails, however, you don't have to specify the URL as the second argument and the HTML-based settings go in to the html option key. Worth opening an issue for this.

Getting a strange error on my routes, "missing required keys" rails 4

So I am getting this error on my localhost:3000. I am making a gif posting blog app and I am trying to add an edit function to items that appear in my _feed_item.html.erb partial. I have posted the error below and a link to some source files in a gist. I believe the routes are ok, but the "missing required keys: [:id]" piece is the one aspect I don't understand. Not sure why this doesn't work as well as my delete function does. Some of this code is based on Hartl's rails tutorial.
app/views/shared/_feed_item.html.erb where line #25 raised:
No route matches {:controller=>"microposts", :action=>"edit"} missing required keys: [:id]
Extracted source (around line #25(see the bold line below)):
</span><br />
<% if current_user?(feed_item.user) %>
**<%= link_to "edit", edit_micropost_path %>**
<%= link_to "delete", feed_item, method: :delete,
data: { confirm: "Are you sure? "}, title: feed_item.content %>
<% end %>
</li>
Link to Gist
Your're almost there. The error message says,
No route matches {:controller=>"microposts", :action=>"edit"} missing required keys: [:id].
The controller has to know which resource (micropost) you are trying to access. Give the id of the resource and you'll be all fine.
**<%= link_to "edit", edit_micropost_path(feed_item.id) %>**
You need to give your edit path a parameter so it knows the id of the micropost to edit.
edit_micropost_path(feed_item)

No route matches [POST] "/story/new" after submitting form

I've just started "Build Your Own Ruby on Rails" and I have had to use Google a lot, as the book seems to have a bunch of places where the code just doesn't work. This time, I couldn't find an answer. Okay, so here's the deal. I have a form that looks like this:
new.html.erb:
<%= form_for :story do |f| %>
<p>
name:<br />
<%= f.text_field :name %>
</p>
<p>
link: <br />
<%= f.text_field :link %>
</p>
<p>
<%= submit_tag %>
</p>
<% end %>
It shows up fine when I go to localhost:3000/story/new. The thing is, when I try to type stuff into the form and press "submit," I get this error:
Routing Error
No route matches [POST] "/story/new"
My routes.rb looks like this:
FirstApp::Application.routes.draw do
resources :story
story_controller looks like this:
def new
#story = Story.new(params[:story])
if request.post?
#story.save
end
end
The story_controller stuff for new is straight out of the book. I thought I might have had a solution here, but no dice. Any help would be greatly appreciated.
I'm guessing you meant (note the at sign):
<%= form_for #story do |f| %>
That'll probably take care of your routing issue, but as John mentions, your controller action is a bit off, too. The new action should only load a dummy model and display the new.html.erb page - the saving should take place in a separate action, called create.
Hope this helps!
Edit: Minimal controller code:
class StoriesController < ApplicationController
def new
#Make a dummy story so any default fields are filled correctly...
#story = Story.new
end
def create
#story = Story.new(params[:story])
if(#story.save)
#Saved successfully; go to the index (or wherever)...
redirect_to :action => :index
else
#Validation failed; show the "new" form again...
render :action => :new
end
end
end
First off, Rails is relies on convention over configuration when using singular vs plural names. If you want to follow convention, you have to change the line in your routes.rb to resources :stories, which would generate following routes:
stories GET /stories(.:format) stories#index
POST /stories(.:format) stories#create
new_story GET /stories/new(.:format) stories#new
edit_story GET /stories/:id/edit(.:format) stories#edit
story GET /stories/:id(.:format) stories#show
PUT /stories/:id(.:format) stories#update
DELETE /stories/:id(.:format) stories#destroy
Note, that in this case you would have to rename your controller to StoriesController. However, your routes.rb has resources :story, which generates following routes:
story_index GET /story(.:format) story#index
POST /story(.:format) story#create
new_story GET /story/new(.:format) story#new
edit_story GET /story/:id/edit(.:format) story#edit
story GET /story/:id(.:format) story#show
PUT /story/:id(.:format) story#update
DELETE /story/:id(.:format) story#destroy
As you can see, indeed, there is no route for POST /story/new. I guess, the error that you are getting is triggered by following code in your controller:
if request.post?
#story.save
end
It is quite wrong, because you trying to check for POST request inside the action that is routed to by GET. Just remove this code from your new action and add create action to your StoryController like this:
def create
#story = params[:story]
if #story.save
redirect_to #story, notice: "Story created"
else
render action: "new"
end
end
This should resolve your issue for now. But I strongly recommend using plural stories for your resources, since it will be back to haunt you again.
This is the part that you (and me) have missed from the guide:
There's one problem with this form though. If you inspect the HTML
that is generated, by viewing the source of the page, you will see
that the action attribute for the form is pointing at /articles/new.
This is a problem because this route goes to the very page that you're
on right at the moment, and that route should only be used to display
the form for a new article.
The form needs to use a different URL in order to go somewhere else.
This can be done quite simply with the :url option of form_for.
Typically in Rails, the action that is used for new form submissions
like this is called "create", and so the form should be pointed to
that action.
Edit the form_for line inside app/views/articles/new.html.erb to look like this:
<%= form_for :story, url: stories_path do |f| %>

Resources