Customize child index of inputs_for form output - html

I am trying to create a form with a list of addresses and allowing the user to delete or create new addresses through Javascript. I’ve used Rails’ fields_for with a child_index: 'new_record' for a similar functionality where I replaced the new_record string with a timestamp when appending the form fields through Javascript (as explained by this Pluralsight tutorial: https://www.pluralsight.com/guides/ruby-on-rails-nested-attributes).
The trick I am looking for is to have similar rendering functionality in Phoenix is how to generate a nested form with a given / custom child index. Currently I am struggling with something like this;
<%= form_for #changeset, Routes.user_path(#conn, :update, #user.id), [data: [controller: "nested-form", action: "nested-form#submit"]], fn f -> %>
<div data-target="nested-form.records">
<%= inputs_for f, :addresses, fn fp -> %>
<%= render __MODULE__, "_address_fields.html", form: fp %>
<% end %>
</div>
<template data-target="nested-form.template">
<%# How do I get a template input group here? %>
<%# In Rails I could do `f.fields_for :addresses, Address.new, child_index: 'NEW_RECORD'` %>
</template>
<% end %>
But I can't figure out how to generate a inputs_for with Phoenix to create such template.

As #TheAnh commented, the answer is discussed in this gist (https://gist.github.com/mjrode/c2939ee7786b157aab131761c8fb89a9). To provide an answer, I've solved it with the following helper method;
defmodule MyAppWeb.UserView do
use MyAppWeb, :view
def template_inputs_for(changeset, field, fun) do
form = Phoenix.HTML.FormData.to_form(changeset, [])
inputs_for(form, field, fn form ->
id = String.replace(form.id, ~r/\d$/, "NEW_RECORD")
name = String.replace(form.name, ~r/\[\d\]$/, "[NEW_RECORD]")
fun.(%{form | id: id, name: name})
end)
end
end
Which can then be used to generate a "template" field group;
<%= form_for #changeset, Routes.user_path(#conn, :update, #user.id), [data: [controller: "nested-form", action: "nested-form#submit"]], fn f -> %>
<div data-target="nested-form.records">
<%= inputs_for f, :addresses, fn fp -> %>
<%= render __MODULE__, "_address_fields.html", form: fp %>
<% end %>
</div>
<template data-target="nested-form.template">
<%= template_inputs_for User.changeset(%User{addresses: [%Address{}]}), :addresses, fn f -> %>
<%= render __MODULE__, "_address_fields.html", form: f %>
<% end %>
</template>
<% end %>

Related

How to select data from API call result in rails?

I’m completely new to ruby on rails, I’m creating a simple article search application that would use the Guardian API and just display the news titles. It just needs to work like this: a user enters the page, fills in the search form and views the news titles.
I want to simply select the request result’s ‘webTitle’ keys and display their values as list items, but I get a big chunk of data and I’m not sure how can I do that.
Here is the request result:
{"response"=>{"status"=>"ok", "userTier"=>"developer", "total"=>2153270, "startIndex"=>1, "pageSize"=>10, "currentPage"=>1, "pages"=>215327, "orderBy"=>"relevance", "results"=>[{"id"=>"books/2017/jul/16/fall-down-7-times-get-up-8-naoki-higashida-review-autism", "type"=>"article", "sectionId"=>"books", "sectionName"=>"Books", "webPublicationDate"=>"2017-07-16T06:00:13Z", "webTitle"=>"Fall Down 7 Times Get Up 8 review – a window on the world of autism", "webUrl"=>"https://www.theguardian.com/books/2017/jul/16/fall-down-7-times-get-up-8-naoki-higashida-review-autism", "apiUrl"=>"https://content.guardianapis.com/books/2017/jul/16/fall-down-7-times-get-up-8-naoki-higashida-review-autism", "isHosted"=>false, "pillarId"=>"pillar/arts", "pillarName"=>"Arts"}, {"id"=>"football/2017/jul/07/gold-cup-2017-predictions-usa-mexico-costa-rica-football", "type"=>"article", "sectionId"=>"football", "sectionName"=>"Football", "webPublicationDate"=>"2017-07-07T09:00:08Z", "webTitle"=>"Gold Cup picks: USA to tip under-strength Mexico and in-form Costa Rica", "webUrl"=>"https://www.theguardian.com/football/2017/jul/07/gold-cup-2017-predictions-usa-mexico-costa-rica-football", "apiUrl"=>"https://content.guardianapis.com/football/2017/jul/07/gold-cup-2017-predictions-usa-mexico-costa-rica-football", "isHosted"=>false, "pillarId"=>"pillar/sport", "pillarName"=>"Sport"}, {"id"=>"world/2017/jul/15/stream-of-floating-bodies-near-mosul-raises-fears-of-reprisals-by-iraqi-militias", "type"=>"article", "sectionId"=>"world", "sectionName"=>"World news", "webPublicationDate"=>"2017-07-15T08:00:01Z", "webTitle"=>"Stream of floating bodies near Mosul raises fears of reprisals by Iraqi militias", "webUrl"=>"https://www.theguardian.com/world/2017/jul/15/stream-of-floating-bodies-near-mosul-raises-fears-of-reprisals-by-iraqi-militias", "apiUrl"=>"https://content.guardianapis.com/world/2017/jul/15/stream-of-floating-bodies-near-mosul-raises-fears-of-reprisals-by-iraqi-militias", "isHosted"=>false, "pillarId"=>"pillar/news", "pillarName"=>"News"}]}}
API consumer class:
#app/clients/guardian_api_client.rb
class GuardianApiClient
include HTTParty
API_KEY = ENV['GUARDIAN_CONTENT_API_KEY']
BASE_URL ="https://content.guardianapis.com/search?"
API_PARTIAL_URL = "api-key=#{API_KEY}"
def query(q)
request = HTTParty.get(BASE_URL+"q=#{q}&""api-key=#{API_KEY}")
puts request
request
end
end
Controller:
class SearchController < ApplicationController
def search
#app = GuardianApiClient.new
#results = #app.query(params[:q])
end
end
View:
<%= form_with(url: '/search') do |f| %>
<%= f.text_field :q %>
<%= f.submit 'search' %>
<% end %>
<% if #results != nil %>
<ul>
<%= #results.each do |r| %>
<li><%= r["webTitle"] %></li>
<% end %>
</ul>
<% else %>
<p>No results yet</p>
<% end %>
Routes:
Rails.application.routes.draw do
get '/search' => 'search#search'
post '/search' => 'search#search'
end
The response is some JSON, so you need to learn how to map through it and get the results that you want.
To see the data more clearly try printing it with:
puts JSON.pretty_generate(#results)
in your controller, then see the output in your rails console.
Anyway, you have a few options:
Option 1: Likely you just need to drill down further into #results in your view. In the JSON that is returned, the webTitles are nested, so changing the third line below should work. Also note on that line that I removed the = sign to prevent the return value from being displayed.
<% if #results != nil %>
<ul>
<% #results["response"]["results"].each do |r| %>
<li><%= r["webTitle"] %></li>
<% end %>
</ul>
<% else %>
<p>No results yet</p>
<% end %>
Option 2: You may consider getting the list of articles in your controller, which I think was your original intent and also is probably more "rails" like:
class SearchController < ApplicationController
def search
#app = GuardianApiClient.new
#results = #app.query(params[:q])
#articles = #results["response"]["results"].map do |article|
article
end
end
end
In your view, then call render to a partial:
<%= render 'articles' %>
Then create a partial view called _articles.html.erb in whatever directory your other view is in, and then add some code to display each article:
<ul>
<% #articles.each do |article| %>
<li><%= article["webTitle"] %> <% link_to 'Link', article["webUrl"] %></li>
<% end %>
<ul>
By separating out each article that was returned in the #articles array, it will probably be easier for you to get other attributes as well in a more readable way. As you can see, above I included a link to the actual article.

Is it possible to check for an integer when using embedded elixir on the front end?

I'm trying to figure out what I can use on the embedded elixir front to check if something is a number.
This is my code
<%= form_for #changeset, #action, fn f -> %>
<%= if #changeset.action do %>
<div class="alert alert-danger">
<p>Oops, something went wrong! Please check the errors below.</p>
</div>
<% end %>
<!--- CAN I CHECK if #action is integer here? -->
<%=if Integer.parse(#action) %>
<div class="form-item">
<%= label f, :shipping_address, class: "is-req" %>
<%= text_input f, :sender_address %>
<%= error_tag f, :label %>
</div>
<div class="form-item">
<%= label f, :Receiver_Group_Name, class: "is-req" %>
<%= text_input f, :reciever_group_name %>
<%= error_tag f, :reciever_group_name %>
</div>
<div class="form-item">
<%= label f, :Shipping_Items, class: "is-req" %>
<%= text_input f, :items %>
<%= error_tag f, :items %>
</div>
<div class="form-item">
<%= label f, :Funding, class: "is-req" %>
<%= text_input f, :funding %>
<%= error_tag f, :funding %>
</div>
<div class="form-item is-text-center">
<%= submit "Submit", class: "button is-big" %>
</div>
<% end %>
So I already know Integer.parse() doesn't work on the front end, but is there anything similar I could use to check a variable? Is there a way I can interface the #action with javascript if not?
First project with elixir/Phoenix, any tips are appreciated.
I already know Integer.parse() doesn't work on the front end”
I doubt I follow what is supposed to mean. The template is processed on the backend side. Integer.parse/2 always returns truthy values, making if Integer.parse(whatever) basically a NoOp.
What do you probably want is to setup another assign in your controller:
it_is_integer =
case Integer.parse(action) do
{_int, ""} -> true
{_int, _} -> false
:error -> false
end
and pass this assign to Phoenix.Controller.render/3, or wherever as (it_is_integer: it_is_integer) and use in your template:
<%= if #it_is_integer %>
Sidenote: I am not familiar with Phoenix, but AFAICT #action is never supposed to be an integer.

Rails: Get form to only render when certain conditions are met

Im trying to get this loop to only render the reviews form for services which doesnt already have a review. I can't get it to function properly. Any ideas?
<% #services.each do |service| %>
<% if service == #booked && !#hasReview %>
<%= form_for(service, service.reviews.new) do |f| %>
<label>Create review for</label> <%= label_tag service.title %>
<div id="user_stars"></div>
<div class form-group>
<%= f.text_area :comment, rows: 3, class: "form-control" %>
</div>
<%= f.hidden_field :service_id, value: service.id %>
<div class="actions">
<%= f.submit "Create", class: "btn btn-primary" %>
</div>
<% end %>
<% end %>
<% end %>
The #booked and #hasReview actions are working correctly by themselves. So I guess Im setting it up wrongly with the IF
EDIT:
services_controller.rb
def show
#user = User.find(params[:id])
#services = #user.services
#booked = Booking.where("service_id = ? AND user_id = ?", #service.id, current_user_id).present? if current_user
#reviews = #service.reviews
#hasReview = #reviews.find_by(user_id: current_user_id) if current_user
end
reviews_controller.rb
def create
#review = current_user.reviews.create(review_params)
redirect_to request.referer
end
Your logic looks good, so I'm guessing your problem is with this part of your if statement:
if service == #booked
Judging from this line in your services_controller:
#booked = Booking.where("service_id = ? AND user_id = ?", #service.id, current_user_id).present? if current_user
it looks like the #booked instance variable is a boolean. So you're comparing a boolean to service, but it doesn't look like service is a boolean.
So you'll want to change the if statement so that you're comparing two equivalent types, and in your case you probably want to compare two boolean values.

index outputs content that isn't in the .html.erb file

I'm following a ruby on rails tutorial to build a simple application using database tables and for some reason my home page outputs more than it should. It creates this array that looks like a database query made with prompt and puts it on the page. I'm pretty sure the problem is with my index.html.erb file (if I empty the file and reload the weird content isn't there), but I can't figure out what's going on. Here's a screenshot of what happens.
controller code:
class BooksController < ApplicationController
def new
#page_title = 'Add Book'
#book = Book.new
#category = Category.new
#author = Author.new
#publisher = Publisher.new
end
def create
#book = Book.new(book_params)
#book.save
redirect_to books_path
end
def update
end
def edit
end
def destroy
end
def index
#books = Book.all
end
def show
end
private
def book_params
params.require(:book).permit(:title, :category_id, :author_id, :publisher_id, :isbn, :price, :buy, :format, :excerpt, :pages, :year, :coverpath)
end
end
html:
<div id= "books-index">
<% #books.each_slice(4) do |book| %>
<div class = "row">
<%= book.each do |book| %>
<div class="col-md-3 col-sm-3">
<h3><%= book.title %></h3>
<%= image_tag(book.coverpath) %>
<%= link_to 'Read More', book_path(book), class:'btn btn-primary' %>
</div>
<% end %>
</div>
<% end %>
</div>
I am new to ruby and ruby on rails, so if I need to post any more resources or info in order to make my question clearer please let me know. Thanks for the help
You should put book.each call inside of <% tag, instead of <%= tag:
<% books.each do |book| %>
Now, you print the result of books.each (which is books array) into your HTML.
<%= book.each do |book| %>
The equal after the opening syntax prints the command(s) that follow. That should be the case, try removing it
remove= from the line <%= book.each do |book| %>

Placing link at top

How do I place a link at the top of my page when the URL that it is pointing to is not determined until later down the page. In this example, I want to move Create and Edit Scenario links to the top of the page, but as you can see Edit Scenario depends on knowing the #scenario_id first.
<%= will_paginate #scens, :next_label => 'Older', :prev_label => 'Newer' %>
<div class="box">
<% for scenario in #scens %>
<% #created = scenario.created_at %>
<% #updated = scenario.updated_at %>
<% #scenario_id = scenario.id %>
<% if scenario.scenario_image.exists? %>
<%= scenario_image_tag(scenario) %>
<% end %>
<%= simple_format(scenario.description) %>
<% end %>
</div>
<% if session[:role_kind] == "controller" %>
<p>
<%= button_to "Create new scenario", :action => "create" %>
<% if #scens.size > 0 %>
<%= button_to "Edit scenario", :action => "edit", :id => #scenario_id %>
<% end %>
</p>
You can add the link at the top but you will need to programmatically access it later and then assign the URL to it. That needs some kind of reference or look-up capability, I'm thinking client-side javascript but that's as I don't know Ruby.
Alternatively you could create the link later when you have the URL and place the link at the top using CSS positioning. The actual position of all the DOM elements on the page need not match the order in which they are rendered.
One way to do this is to use a helper:
In your helper.rb file:
def stack_example(scens, &block)
html = 'Scenario Details'
edit_link = 'Edit Link'
yield html, edit_link
end
Then in your partial you could have something like:
<% stack_example(#scens) do |html, edit_link| %>
<%= edit_link %><br>
<%= html %>
<% end %>
Should output the following:
Edit Link
Scenario Details
I don't get it. Why do you create model in the view layer? Why wouldn't you create the model variables in the controller? Sth like:
class your_controller
def your_method
#scenario_id = ...
end
end
I think that your problem lays in the invalid MVC usage. Don't you think that all the #member #variables should be initialized before the view starts to render?