Is there a way to check if part of the URL contains a certain string - ruby-on-rails-4

Is there a way to check if part of the URL contains a certain string:
Eg. <% if current_spree_page?("/products/*") %>, where * could be anything?

I tested, and gmacdougall's answer works, I had already found a solution though.
This is what I used to render different layouts depending on what the url is:
url = request.path_info
if url.include?('products')
render :layout => 'product_layout'
else
render :layout => 'layout'
end
The important thing to note is that different pages will call different methods within the controller (eg. show, index). What I did was put this code in its own method and then I am calling that method where needed.

If you are at a place where you have access to the ActionDispatch::Request you can do the following:
request.path.start_with?('/products')

You can use include? method
my_string = "abcdefg"
if my_string.include? "cde"
puts "String includes 'cde'"
end`
Remember that include? is case sensetive. So if my_string in the example above would be something like "abcDefg" (with an uppercase D), include?("cde") would return false. You may want to do a downcase() before calling include?()

The other answers give absolutely the cleanest ways of checking your URL. I want to share a way of doing this using a regular expression so you can check your URL for a string at a particular location in the URL.
This method is useful when you have locales as first part of your URL like /en/users.
module MenuHelper
def is_in_begin_path(*url_parts)
url_parts.each do |url_part|
return true if request.path.match(/^\/\w{2}\/#{url_part}/).present?
end
false
end
end
This helper method picks out the part after the second slash if the first part contains 2 word characters as is the case if you use locales. Drop this in your ApplicationController to have it available anywhere.
Example:
is_in_begin_path('users', 'profile')
That matches /en/users/4, /en/profile, /nl/users/9/statistics, /nl/profile etc.

Related

How can I use regex to construct an API call in my Jekyll plugin?

I'm trying to write my own Jekyll plugin to construct an api query from a custom tag. I've gotten as far as creating the basic plugin and tag, but I've run into the limits of my programming skills so looking to you for help.
Here's my custom tag for reference:
{% card "Arbor Elf | M13" %}
Here's the progress on my plugin:
module Jekyll
class Scryfall < Liquid::Tag
def initialize(tag_name, text, tokens)
super
#text = text
end
def render(context)
# Store the name of the card, ie "Arbor Elf"
#card_name =
# Store the name of the set, ie "M13"
#card_set =
# Build the query
#query = "https://api.scryfall.com/cards/named?exact=#{#card_name}&set=#{#card_set}"
# Store a specific JSON property
#card_art =
# Finally we render out the result
"<img src='#{#card_art}' title='#{#card_name}' />"
end
end
end
Liquid::Template.register_tag('cards', Jekyll::Scryfall)
For reference, here's an example query using the above details (paste it into your browser to see the response you get back)
https://api.scryfall.com/cards/named?exact=arbor+elf&set=m13
My initial attempts after Googling around was to use regex to split the #text at the |, like so:
#card_name = "#{#text}".split(/| */)
This didn't quite work, instead it output this:
[“A”, “r”, “b”, “o”, “r”, “ “, “E”, “l”, “f”, “ “, “|”, “ “, “M”, “1”, “3”, “ “]
I'm also then not sure how to access and store specific properties within the JSON response. Ideally, I can do something like this:
#card_art = JSONRESPONSE.image_uri.large
I'm well aware I'm asking a lot here, but I'd love to try and get this working and learn from it.
Thanks for reading.
Actually, your split should work – you just need to give it the correct regex (and you can call that on #text directly). You also need to escape the pipe character in the regex, because pipes can have special meaning. You can use rubular.com to experiment with regexes.
parts = #text.split(/\|/)
# => => ["Arbor Elf ", " M13"]
Note that they also contain some extra whitespace, which you can remove with strip.
#card_name = parts.first.strip
#card_set = parts.last.strip
This might also be a good time to answer questions like: what happens if the user inserts multiple pipes? What if they insert none? Will your code give them a helpful error message for this?
You'll also need to escape these values in your URL. What if one of your users adds a card containing a & character? Your URL will break:
https://api.scryfall.com/cards/named?exact=Sword of Dungeons & Dragons&set=und
That looks like a URL with three parameters, exact, set and Dragons. You need to encode the user input to be included in a URL:
require 'cgi'
query = "https://api.scryfall.com/cards/named?exact=#{CGI.escape(#card_name)}&set=#{CGI.escape(#card_set)}"
# => "https://api.scryfall.com/cards/named?exact=Sword+of+Dungeons+%26+Dragons&set=und"
What comes after that is a little less clear, because you haven't written the code yet. Try making the call with the Net::HTTP module and then parsing the response with the JSON module. If you have trouble, come back here and ask a new question.

What is best practice for passing variables via GET?

I am passing a variable in my URL:
mydomain.com/app/?next_page=my_page
I can get this variable in a view with:
def mypage(request):
var = request.GET['next_page']
Is it best practice to also change the URL to require next_page? Something along the lines of:
path('app/?nextpage=<str>', mypage, name='my_page')
What's best practice? If so, what's the correct syntax for this (I know the example is incorrect)?
It depends on your needs.
Do not define a fixed url route; if you use the query parameters for filtering and there is more than one possible parameter
Example: "app/photos?size=100x100" and "app/photos/?color=blue"
Define a fixed url route; if it will be the same for each and every page, like details of a particular page:
Example: "app/orders/123123123" and "app/orders/123123123"
Btw, the correct syntax is:
path(app/<str:next_page>/, mypage, name="my_page")
You should take a look at path patterns. Enforcing a GET parameter in a path is not really a good practice. So if you want to require a username for example you can use:
path('bio/<username>/', views.bio, name='bio'),
You can find more patterns in Django documentation to catch strings, slugs, integers etc.
And in views you should define your function as such:
def mypage(request, username):
...code...
About GET:
Keep in mind that request.GET["value"] will raise a ValueError if that parameter does not exist. So you can catch that error to inform user that they are missing a parameter. (This will make this parameter obligatory.)
You can also use request.GET.get("value") which will return None if the key does not exist. If you want to use a default parameter you can use of course, request.GET.get("value", "default")
You can use as many parameters as you want in your link with or without path patterns. Their values will be stored in request.GET

Is there any maximum length of character regex can handle?

I'm stack in making my regex work in Python3.5.
I have a list which contains a lot of URLs.
Some URLs are short, others are long.
I could excerpt URLs I wanted...mostly but only this URL cannot be excerpted.
http://www.forbes.com/sites/julianmitchell/2016/09/27/this-startup-uses-drones-to-map-and-manage-massive-construction-projects/#1ca4d634334e
Here is the code.
urlList=[] # Assume there are many URLs in this list.
interdrone = re.compile(r"http://www.interdrone.com/news/(?:.*)")
hp = re.compile(r"http://www.interdrone.com/$")
restOfThem=re.compile(r'\#|youtube|bzmedia|facebook|twitter|mailto|geoconnexion.com|linkedin|gplus|resources\.sdtimes\.com|precisionagvision')
cleanuplist =[] # Adding URLs I need to this new list.
for i in range(0,len(urlList)):
if restOfThem.findall(ursList[i]):
continue
elif hp.findall(urlList[i]):
continue
elif interdrone.findall(urlList[i]):
cleanuplist.append(urlList[i])
else:
cleanuplist.append(urlList[i])
logmsg("Generated Interdrone clean URL list")
return (cleanuplist)
forbes.com URL should fall into "else:" clause, so it should be added to cleanuplist. However, it is not. Again, only this one is not added to the new list.
I tried to pick specifically Forbes site by this,
forbes = re.compile(r"http://www.forbes.com/(?:.*)")
then, add following elif statement.
elif forbes.findall(urlList[i]):
cleanuplist.append(urlList[i])
However, it also does not pick up forbes site.
Therefore, I come to doubt there is some kind of maximum boundary of character to apply regex (so that findall is skipped?).
I could be wrong. How can I excerpt forbes.com site above?
Your regex matches the URL you provided, specifically the # that's present in the last part of your URL. That's why it is skipped. There is no "character limit" (unless Python runs out of memory).
You need to be more restrictive with the regex. For example, what if your URL had been http://www.forbes.com/sites/julianmitchell/2016/09/27/twitter-stock-down - should it have matched the twitter part of your regex?
Also, you probably want to use re.search(), not re.findall().
Furthermore, you don't seem to need the last elif clause since the same thing will happen whether it's true or not.
Lastly, the correct way to iterate would be for url in urlList: instead of using indexes. This is Python, not Java.

In Django, how do I deal with an "or" in the url regex once I get to the view?

I'm just learning Django, and am getting stuck with some url logic. I'm trying to allow either a category name or id in the url:
...
url(r'^(?P<booze_q>\w+|\d+)/$','glasses.views.booze'),
...
And then in thew view, only deal with that result once. However, if the url is a string - in this case, Whiskey, I get an error for trying to pass a string where an int is expected. This is the closest I've gotten so far:
def booze(request, booze_q):
booze = get_object_or_404(Booze,Q(pk=booze_q)|Q(name=booze_q))
return render_to_response('booze/detail.html', {'booze': booze})
But this returns an error: invalid literal for int() with base 10: 'Whiskey'
I'm sure it's a pretty easy thing, but this is my first Django app, so any help would be appreciated.
tl;dr: End result, I'd like mysite.com/1/ or mysite.com/Whiskey/ to both call the glasses.views.booze view, and get the object with id=1 or name=Whiskey
This is a common scenario you'll encounter quite often, which is typically handled by resorting to multiple arguments and having views behave differently based on which of the view arguments are then present or not.
What you do is first define a URL pattern that uniquely matches each specific case and then let Django's URL resolver set the arguments accordingly based on which of the patterns was matched.
Here's an example with a class based view, that performs two different queries based on which of the two keyword arguments, booze_id or booze_name, is set:
url(r'^(?P<booze_id>\d+)/$', BoozeDetailView.as_view()),
url(r'^(?P<booze_name>\w+)/$', BoozeDetailView.as_view()),
class BoozeDetailView(DetailView):
model = Booze
def get_object(self):
booze_id = self.kwargs.get('booze_id', None)
booze_name = self.kwargs.get('booze_name', None)
if booze_id:
return self.model.objects.get(id=booze_id)
else:
return self.model.objects.get(name=booze_name)
You will always get a string, even if the string contains a number.
1) You should not have a parameter that could be either an id or something else. One day you will enter an item whose name is a number and your app will fail.
2) When querying for pk with a string django automatically tries to convert it into an integer. You'll have to handle the non-pk case before constructing that query.

Django URL match in HttpResponse object?

In django, when a URL is matched, the match group is passed as a second parameter to the view function, the first being a HttpRequest object. For example, with a URL patter like this
'/foo/(\d{2})/', 'app.views.handler'
the handler routine will have
def handler(request, value):
where value will contain a two digit number (as a string).
My question is: is value also contained in the request object, and if yes, how can I get it (of course, parsing the URL from the request object is not an option, too impractical).
Thanks
I'm not going to debate the merit of your idea. Just try to answer your question:
No there is no way, other than applying the regex to the URL again, to get at the url parameter.
Your view will be the first point where the parameter list will be available. Why don't you just create a wrapper object to encapsulate your request and your parameter list at that point?
Just pass that around...
Can you give any reason why you would need this?
I don't see why parsing the url path is 'impractical', given that you've already got a regexp that works, in your urlconf.